日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

BZOJ5249: [2018多省省队联测]IIIDX(线段树 贪心)

發布時間:2024/4/14 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 BZOJ5249: [2018多省省队联测]IIIDX(线段树 贪心) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題意

題目鏈接

Sol

不難發現題目給出的是一個樹,其中\(\frac{i}{K}\)\(i\)的父親節點

首先,當\(d_i\)互不相同時,一個顯然的貪心策略就是優先給編號小的分配較大的權值。可以排序后dfs完成。

但是,當\(d_i\)相同時,可能存在這樣一種情況:把編號小的子樹內權值較大的節點,和某個編號較大的根交換后,仍然滿足要求

比如\(N = 4, K = 2, a = {1, 1, 1, 2}\)

此時直接貪心的話會輸出\(1, 1, 1, 2\),實際上最優解為\(1, 1, 2, 1\)

這時候怎么辦呢?

考慮一個節點\(p\)可以選擇權值為\(x\)的條件是什么,因為該節點子樹內的權值一定都比\(x\)

因此對于每個權值小于\(x\)的數,權值比它大且可以選擇的數至少為\(siz[p]\)

同時根據貪心的策略,先遍歷到的節點應該選大的權值。

這樣就不難得到一個算法:

首先按權值從大到小排序,同時用線段樹維護出每個位置權值比它大且能選擇的位置個數

對于每個點\(p\),在線段樹上二分出最大的滿足條件的位置\(x\)。同時,當權值相同時,該位置應該更靠右。

然后再在區間\([x, n]\)中的所有點減去\(siz[x]\)

注意一個細節,當遍歷到某個節點時,應該消去父親對他的影響

寫完代碼 -> 過樣例 -> 1A hhhhhh(雖然是抄的)

60分

#include<bits/stdc++.h> #define sz(x) (int)x.size() using namespace std; const int MAXN = 5e5 + 10; inline int read() {char c = getchar(); int x = 0, f = 1;while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();return x * f; } int N; double K; int a[MAXN], ans[MAXN], res; vector<int> v[MAXN]; int AddEdge(int x, int y) {v[x].push_back(y); } void dfs(int x) {for(int i = 0; i < sz(v[x]); i++) dfs(v[x][i]);if(x) ans[x] = a[res--]; } int main() {scanf("%d%lf", &N, &K); res = N;//printf("%lf\n", K);for(int i = 1; i <= N; i++) {int pre = (int) floor(i / K);a[i] = read(); AddEdge(pre, i);}sort(a + 1, a + N + 1);dfs(0);for(int i = 1; i <= N; i++) printf("%d ", ans[i]);return 0; }

AC代碼

#include<bits/stdc++.h> using namespace std; const int MAXN = 5e5 + 10; inline int read() {char c = getchar(); int x = 0, f = 1;while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();return x * f; } int N; double K; int cnt[MAXN], fa[MAXN], siz[MAXN], ans[MAXN], a[MAXN]; #define ls k << 1 #define rs k << 1 | 1 struct Node {int l, r, f, mn; }T[MAXN << 2]; void update(int k) {T[k].mn = min(T[ls].mn, T[rs].mn); } void add(int k, int val) {T[k].f += val; T[k].mn += val; } void pushdown(int k) {if(!T[k].f) return ;add(ls, T[k].f); add(rs, T[k].f); T[k].f = 0; } void Build(int k, int ll, int rr) {T[k] = (Node) {ll, rr, 0, 0};if(ll == rr) {T[k].mn = ll; return ;}int mid = ll + rr >> 1;Build(ls, ll, mid); Build(rs, mid + 1, rr); update(k); } void IntervalAdd(int k, int ll, int rr, int val) {if(ll <= T[k].l && T[k].r <= rr) {add(k, val); return ;}pushdown(k);int mid = T[k].l + T[k].r >> 1;if(ll <= mid) IntervalAdd(ls, ll, rr, val); if(rr > mid) IntervalAdd(rs, ll, rr, val);update(k); } int Query(int k, int sz) {if(T[k].l == T[k].r) return T[k].mn >= sz ? T[k].l : T[k].l + 1;pushdown(k);if(T[rs].mn >= sz) return Query(ls, sz);else return Query(rs, sz); } int main() {N = read(); cin >> K;for(int i = 1; i <= N; i++) {a[i] = read();int t = (int) floor(i / K); fa[i] = t; siz[i] = 1;}for(int i = N; i >= 0; i--) siz[fa[i]] += siz[i];Build(1, 1, N); sort(a + 1, a + N + 1, greater<int>());for(int i = N - 1; i >= 1; i--) cnt[i] = (a[i] == a[i + 1] ? cnt[i + 1] + 1 : 0);for(int i = 1; i <= N; i++) {if(fa[i] && fa[i] != fa[i - 1]) IntervalAdd(1, ans[fa[i]], N, siz[fa[i]] - 1);int t = Query(1, siz[i]); t += cnt[t]; cnt[t]++; t -= (cnt[t] - 1); ans[i] = t;IntervalAdd(1, t, N, -siz[i]);}for(int i = 1; i <= N; i++) printf("%d ", a[ans[i]]);return 0; }

總結

以上是生活随笔為你收集整理的BZOJ5249: [2018多省省队联测]IIIDX(线段树 贪心)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。