1. 程式人生 > 其它 >Till I Collapse CodeForces - 786C 主席樹

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;
}