5249: [2018多省省队联测]IIIDX
5249: [2018多省省队联测]IIIDX
分析:
贪心。
将给定的权值从大到小排序,从第一个往后挨个赋值,考虑第i个位置可以赋值那些树。首先满足前面必须至少有siz[i]个权值没选,如果存在相同的数,尽量往后选。
那么可以给每个权值记录一个值F[i],表示i左边可以选多少个权值了。还要和后面的取一个最小值才是真正的能选多少个。
在线段树上分治找到这个位置。
注意在bzoj上,fa[i]=int(1.0*i/k) 有精度误差,而写成floor就可以了。
代码:
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<cctype> #include<set> #include<queue> #include<vector> #include<map> #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1 | 1 using namespace std; typedef long long LL; inline int read() { int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; } const int N = 500005; int Mn[N << 2], tag[N << 2], R[N], fa[N], siz[N], ans[N], cnt[N], w[N]; inline bool cmp(int x,int y) { return x > y; } inline void pushup(int rt) { Mn[rt] = min(Mn[rt << 1], Mn[rt << 1 | 1]); } inline void pushdown(int rt) { tag[rt << 1] += tag[rt];tag[rt << 1 | 1] += tag[rt]; Mn[rt << 1] += tag[rt];Mn[rt << 1 | 1] += tag[rt]; tag[rt] = 0; } void build(int l,int r,int rt) { tag[rt] = 0; if (l == r) { Mn[rt] = l; return ; } int mid = (l + r) >> 1; build(lson); build(rson); pushup(rt); } void update(int l,int r,int rt,int L,int R,int v) { if (L <= l && r <= R) { tag[rt] += v; Mn[rt] += v; return ; } if (tag[rt]) pushdown(rt); int mid = (l + r) >> 1; if (L <= mid) update(lson, L, R, v); if (R > mid) update(rson, L, R, v); pushup(rt); } int query(int l,int r,int rt,int x) { if (l == r) return l + (Mn[rt] < x); if (tag[rt]) pushdown(rt); int mid = (l + r) >> 1; if (x <= Mn[rt << 1 | 1]) return query(lson, x); else return query(rson, x); } int main() { int n = read(); double k; scanf("%lf", &k); for (int i = n; i >= 1; --i) fa[i] = floor(1.0 * i / k), siz[i] ++, siz[fa[i]] += siz[i]; for (int i = 1; i <= n; ++i) w[i] = read(); sort(w + 1, w + n + 1, cmp); build(1, n, 1); for (int i = n; i >= 1; --i) { if (w[i] == w[i + 1]) R[i] = R[i + 1]; else R[i] = i; } for (int i = 1; i <= n; ++i) { if (fa[i] && fa[i] != fa[i - 1]) update(1, n, 1, ans[fa[i]], n, siz[fa[i]] - 1); int x = query(1, n, 1, siz[i]); x = R[x]; cnt[x] ++; x -= cnt[x] - 1; ans[i] = x; update(1, n, 1, x, n, -siz[i]); } for (int i = 1; i <= n; ++i) printf("%d ", w[ans[i]]); return 0; }