/* 题目转换为 n个节点的一片森林,n个权值,要给每个节点分配一个权值,保证子节点的权值不小于父节点的权值,并且1~n的权值的字典序最大。 考场上的贪心很显然 建立出 树来 将所有数值从大到小排序 然后后序遍历依次填进去 这样就可以处理 互不相同的数据 然后一旦有相同的就会gg 正解 考虑从前往后贪心 我们把所有的数字按照从大到小排序, 然后从前往后贪心 每个位置贪心找当前能放的最大的,也就是保证子树元素都比改点大, 如果有相同的, 令我们选择在序列中最靠右的,这样才有可能将较大的留给后面的 对于数列构建线段树 令res[i] 表示第i个元素以及他左边 空余的元素有多少个 每次查询在线段树上二分 找到这个元素之后 体会一下他的所有孩子都会比这个元素大 所以res[i - n] 都要减去sz[i] 这个限制 当我们遍历该节点的第一个孩子时 将其去除即可 */ #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<iostream> #define M 500010 #define fa(x) (int) floor((x) / (k)) #define inf 1000000000 using namespace std; int read() { int nm = 0, f = 1; char c = getchar(); for(; !isdigit(c); c = getchar()) if(c == '-') f = -1; for(; isdigit(c); c =getchar() ) nm = nm * 10 + c - '0'; return nm * f; } int n, res[M << 2], lazy[M << 2], note[M], b[M], sz[M], ans[M], cnt[M]; double k; void pushup(int now) { res[now] = min(res[now << 1], res[now << 1 | 1]); } void pushdown(int now) { if(!lazy[now]) return; lazy[now << 1] += lazy[now], res[now << 1] += lazy[now], lazy[now << 1 | 1] += lazy[now], res[now << 1 | 1] += lazy[now]; lazy[now] = 0; } void build(int l, int r, int now) { if(l > r) return; if(l == r) { res[now] = l; return; } int mid = (l + r) >> 1; build(l, mid, now << 1); build(mid + 1, r, now << 1 | 1); pushup(now); } void modify(int l, int r, int now, int ln, int rn, int ver) { if(l > rn || r < ln) return ; if(l >= ln && r <= rn) { res[now] += ver; lazy[now] += ver; return; } int mid = (l + r) >> 1; pushdown(now); modify(l, mid, now << 1, ln, rn , ver); modify(mid + 1, r, now << 1 | 1, ln, rn,ver); pushup(now); } int query(int l, int r, int now, int k) { if(l == r) return (res[now] >= k) ?l : l + 1; int mid = (l + r) >> 1; pushdown(now); if(k <= res[now << 1 | 1]) return query(l, mid ,now << 1, k); return query(mid + 1, r, now << 1 | 1, k); } int main() { n = read(); cin >> k; for(int i = 1; i <= n; i++) note[i] = read(), sz[i] = 1; sort(note + 1, note + n + 1, greater<int>() ); for(int i = n; i >= 1; i--) { if(note[i] == note[i + 1]) cnt[i] = cnt[i + 1] + 1; else cnt[i] = 0; sz[fa(i)] += sz[i]; } build(1, n, 1); for(int i = 1; i <= n; i++) { if(fa(i) && fa(i) != fa(i - 1)) modify(1, n, 1, ans[fa(i)], n, sz[fa(i)] - 1); int op = query(1, n, 1, sz[i]); op += cnt[op],cnt[op]++,op -= (cnt[op] - 1),ans[i] = op; modify(1, n, 1, op, n, -sz[i]); } for(int i = 1; i <= n; i++) cout << note[ans[i]] << " "; return 0; }
SDOI2018IIIDX
猜你喜欢
转载自www.cnblogs.com/luoyibujue/p/9250671.html
今日推荐
周排行