「九省联考 2018」IIIDX(贪心+线段树(平衡树)):

https://loj.ac/problem/2472

\(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;
}
posted @ 2020-03-29 16:40  Cold_Chair  阅读(301)  评论(0编辑  收藏  举报