Till I Collapse CodeForces - 786C 主席树

对于每个数字\(a_i\) ,我们都建立一个新的版本,如果之前已经出现过,假设位置为\(last_{a_i}\)就在第 \(i\) 个版本的 \(last_{a_i}\) 删去,然后在新的位置更新
这样的话,对于每个k,我们从第n个版本开始,查询子树大小为 \(i+1\) ,且最左边的的数字出现的版本,然后更新,不停的查询然后更新答案
具体看代码

//主席树
//难以处理区间修改操作,很难处理懒标记
//l,r代表左右子节点的下标
//cnt表示当前区间中一共多少个数

//离散化
//在数值上建立线段树,维护每个数值区间中一共多少个数
//
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 200010;
int n, m;
int a[N];
int b[N];
vector<int> nums;
int last[N];
struct Node {
	int l, r;
	int cnt;
} tr[N << 5];
int root[N << 5], idx;
//建树,原始的,没插入数字的树
void build(int &p, int l, int r) {
	p = ++ idx;
	if (l == r)
		return ;
	//左右儿子
	int mid = l + r >> 1;
	build(tr[p].l, l, mid), build(tr[p].r, mid + 1, r);
}
void del(int &p,int pre,int l,int r,int pos) {
	p=++idx;
	tr[p]=tr[pre];
	if(l==r) {
		tr[p].cnt=0;
		return ;
	}

	int mid=l+r>>1;
	if(pos>mid)
		del(tr[p].r,tr[pre].r,mid+1,r,pos);
	else
		del(tr[p].l,tr[pre].l,l,mid,pos);
	tr[p].cnt=tr[tr[p].l].cnt + tr[tr[p].r].cnt;
}
void add(int &p,int pre,int l,int r,int pos) {
	p=++idx;
	tr[p]=tr[pre];
	if(l==r) {
		tr[p].cnt=1;
		return ;
	}

	int mid=l+r>>1;
	if(pos>mid)
		add(tr[p].r,tr[pre].r,mid+1,r,pos);
	else
		add(tr[p].l,tr[pre].l,l,mid,pos);
	tr[p].cnt=tr[tr[p].l].cnt + tr[tr[p].r].cnt;
}

int find (int p, int l, int r, int k) {
	if (l == r && k != 1)
		return -1;
	else if (l == r)
		return l;

	int mid = l + r >> 1;
	if(tr[tr[p].r].cnt>=k)
		return find(tr[p].r, mid + 1, r, k);
	return find(tr[p].l, l, mid, k-tr[tr[p].r].cnt);
}
int main() {

	cin >> n;
	build(root[0], 1, n);
	for(int i=1; i<=n; i++) {
		int x;
		cin>>x;
		if(last[x])
			del(root[i],root[i-1],1,n,last[x]);
		else
			root[i]=++idx,tr[root[i]]=tr[root[i-1]];
		add(root[i],root[i],1,n,i);
		last[x]=i;
	}
	for(int i=1; i<=n; i++) {
		int ans=0,pr=n;
		while(pr>0) {
			if(tr[root[pr]].cnt<=i) {
				ans++;
				break;
			}
			pr=find(root[pr],1,n,i+1);
			ans++;
		}
		cout<<ans<<" ";
	}
	cout<<endl;
	return 0;
}

posted @ 2021-07-25 13:06  晴屿  阅读(54)  评论(0编辑  收藏  举报