「九省联考 2018」IIIDX(贪心+线段树(平衡树)):
\(i\)到\(i/k\)连一条边,就构成了一个森林,先将d排序。
一个点的取值必须是子树内最大的。
考虑当\(d[i]\)互不相同的话,只需要按顺序,给每个子树分配尽量大的价值即可。
如果x为根的子树必须在\([l,r]\)里,那么对于新来的x的一个子节点的子树y,给它分配\([r-siz[y]+1,r]\)即可。
当\(d[i]\)有相同时,我们就不一定是分配\(r-siz[y]+1\)了,应该是分配\(d[r-siz[y]+1]\)这个值。
这样,可以留出一些大的空位,给其它树用,当然,可能还是自己用掉。
记\(la[i]\),表示\(d[la[i]]=d[i]且d[la[i]-1]≠d[i]\)
每次令x选 能选的最大的位置w的la,然后先假设它的子树占据了接下来的最小的若干位置。
如何求出每次的w,可以用平衡树(treap支持分裂和合并)暴力维护现在还没被选的权值。
注意求一个点x的w之前要把父亲替他选的位置先加回来。
另一种方法就是用线段树维护\(f[i]\)表示\(>=d[i]\)的权值还剩多少个。
初值\(f[i]=n-i+1\)
每次查就在线段树二分一个最左的位置使\(f[j]<siz[x]\),那么\(w=j-1\)。
再使\(w=la[w]\),那么x就选\(d[w]\)了,然后给\(f[1..w]-=siz[x]\)
事实上,根据定义,可能是要给\(f[w+1..n]\)减去一个等差数列的,事实上\(f[w]\)的限制已经足以代表这个限制,所以可以忽略。
Code:
#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i < _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;
#define db double
#define V vector<int>
#define pb push_back
#define si size()
const int N = 5e5 + 5;
db k;
int n, d[N], la[N], siz[N], fa[N];
#define i0 i + i
#define i1 i + i + 1
int t[N * 4], lz[N * 4], pl, pr, px;
void bt(int i, int x, int y) {
if(x == y) {
t[i] = n - x + 1;
return;
}
int m = x + y >> 1;
bt(i0, x, m); bt(i1, m + 1, y);
t[i] = min(t[i0], t[i1]);
}
void ad(int i, int x) { if(i) t[i] += x, lz[i] += x;}
void down(int i) {
if(lz[i]) {
ad(i0, lz[i]); ad(i1, lz[i]);
lz[i] = 0;
}
}
void add(int i, int x, int y) {
if(y < pl || x > pr) return;
if(x >= pl && y <= pr) {
ad(i, px); return;
}
int m = x + y >> 1; down(i);
add(i0, x, m); add(i1, m + 1, y);
t[i] = min(t[i0], t[i1]);
}
int py;
void ef(int i, int x, int y) {
if(t[i] >= px || y < pl || x > pr) return;
if(x == y) { py = x; return;}
int m = x + y >> 1; down(i);
ef(i0, x, m); if(py > n) ef(i1, m + 1, y);
}
int st[N];
int main() {
scanf("%d %lf", &n, &k);
fo(i, 1, n) scanf("%d", &d[i]);
sort(d + 1, d + n + 1);
fo(i, 0, n) siz[i] = 1, fa[i] = (int) ((db) i / k);
fd(i, n, 1) siz[fa[i]] += siz[i];
fo(i, 1, n) {
if(i > 1 && d[i] == d[i - 1])
la[i] = la[i - 1]; else la[i] = i;
}
bt(1, 1, n);
fo(i, 1, n) {
st[i] = st[fa[i]] + 1;
pl = 1, pr = st[fa[i]], px = siz[i];
add(1, 1, n);
pl = st[i], pr = n, px = siz[i], py = n + 1;
ef(1, 1, n);
py --;
py = la[py];
pl = 1, pr = py; px = -siz[i];
add(1, 1, n);
st[i] = py;
pp("%d ", d[py]);
}
hh;
}
转载注意标注出处:
转自Cold_Chair的博客+原博客地址