洛谷 P6136 【【模板】普通平衡树(数据加强版)】

爱死替罪羊树了


这种暴力的数据结构爱死了。什么?!你还不知道替罪羊树?那就看看这篇博客这篇博客吧。替罪羊树就是当不平衡时,拍扁重建,然后就平衡了。想切这道题,要先把普通平衡树那道题做了(这篇博客讲了的哦),然后就会发现,只要改一下以前的程序就可以了。这里我就着重讲下主函数怎么建树那里。

建树方法:

  1. 一开始我写的方法(指读入建树的时候),长一些,详细的都在代码里面了:
#include <bits/stdc++.h>
using namespace std;
int read(){
    int ans = 0;
	char ch = getchar();
    while(ch > '9' || ch < '0') ch = getchar();
    while(ch <= '9' && ch >= '0'){
        ans = ans * 10 + ch - '0';
        ch = getchar();
    }
    return ans;
}
struct node{
	int ls , rs , f , tsize , fsize , date;
};
node a[2000010];
int memo[2000010] , c[2000010] , ha[2000010];
double alpha = 0.75;
int n , m , root , pool , poi , last , ans;
bool cheak(int now){
	if((double)a[now].fsize * alpha >= (double)max(a[a[now].ls].fsize , a[a[now].rs].fsize)) return true;
	return false;
}
void dfs(int now){
	if(!now) return;
	dfs(a[now].ls);
	if(a[now].f) c[++poi] = now;
	else memo[++pool] = now;
	dfs(a[now].rs);
}
void build(int l , int r , int &now){
	int mid = (l + r) / 2;
	now = c[mid];
	if(l == r){
		a[now].ls = a[now].rs = 0;
		a[now].fsize = a[now].tsize = 1;
		return;
	}
	if(l < mid) build(l , mid - 1 , a[now].ls);
	else a[now].ls = 0;
	build(mid + 1 , r , a[now].rs);
	a[now].fsize = a[a[now].ls].fsize + a[a[now].rs].fsize + 1;
	a[now].tsize = a[a[now].ls].tsize + a[a[now].rs].tsize + 1;
}
void rebuild(int &now){
	poi = 0;
	dfs(now);
	if(poi) build(1 , poi , now);
	else now = 0;
}
void insert(int &now , int t){
	if(!now){
		now = memo[pool--];
		a[now].date = t;
		a[now].fsize = a[now].tsize = a[now].f = 1;
		a[now].ls = a[now].rs = 0;
		return;
	}
	a[now].fsize++ , a[now].tsize++;
	if(a[now].date >= t) insert(a[now].ls , t);
	else insert(a[now].rs , t);
	if(!cheak(now)) rebuild(now);
}
int ft(int rk){
	int now = root;
	while(now){
		if(a[now].f && a[a[now].ls].fsize + 1 == rk) return a[now].date;
		if(a[a[now].ls].fsize + a[now].f >= rk) now = a[now].ls;
		else{
			rk -= a[a[now].ls].fsize + a[now].f;
			now = a[now].rs;
		}
	}
}
int frk(int t){
	int now = root , ans = 1;
	while(now){
		if(a[now].date >= t) now = a[now].ls;
		else{
			ans += a[a[now].ls].fsize + a[now].f;
			now = a[now].rs;
		}
	}
	return ans;
}
void delet(int &now , int rk){
	if(a[now].f && a[a[now].ls].fsize + 1 == rk){
		a[now].f = 0;
		a[now].fsize--;
		return;
	}
	a[now].fsize--;
	if(a[now].f + a[a[now].ls].fsize >= rk) delet(a[now].ls , rk);
	else delet(a[now].rs , rk - a[now].f - a[a[now].ls].fsize);
}
void rdelet(int t){
	delet(root , frk(t));
	if(a[root].tsize * alpha >= a[root].fsize) rebuild(root);
}
int main(){
	n = read() , m = read();
	for(int i = 1; i <= n; i++) ha[i] = read();
	sort(ha + 1 , ha + n + 1);	//手动中序遍历 
	for(int i = 2000000; i >= 1; i--) memo[i] = ++pool;
	for(int i = 1; i <= n; i++){
		c[i] = i;	//模拟dfs操作 
		a[i].date = ha[i];	//把值放回去 
		a[i].f = 1;	//这个点存在 
	}
	pool -= n;	//用了n个内存,内存池里面取n出来 
	build(1 , n , root);	//建树 
	while(m--){
		int opt , x , y;
		opt = read() , x = read();
		x = last ^ x;
		if(opt == 1) insert(root , x);
		if(opt == 2) rdelet(x);
        if(opt == 3) y = frk(x) , ans = ans ^ y , last = y;
        if(opt == 4) y = ft(x) , ans = ans ^ y , last = y;
        if(opt == 5) y = ft(frk(x) - 1) , ans = ans ^ y , last = y;
        if(opt == 6) y = ft(frk(x + 1)) , ans = ans ^ y , last = y;
	}
	cout << ans;
	return 0;
}
  1. 同学写的,短了很多啊,但是似乎我要快一点,我也不知道为什么,可能是因为直接insert的话,数据专门把树卡成链后,重建次数太多,导致要慢一点,而我直接sort快一些(大雾):
for(register int i = 1; i <= n; i++){
	x = read();
	insert(root , x);
}

吐槽:这道题数据还是有点水吧,比较未加强数据的直接搬过来能AC,可能是为了卡朝鲜树之类的数据结构吧。

posted @ 2020-06-16 16:32  那一条变阻器  阅读(173)  评论(0编辑  收藏  举报