• 洛谷 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,可能是为了卡朝鲜树之类的数据结构吧。

  • 相关阅读:
    mongodb根据id获取时间戳
    System.MissingMethodException: 找不到方法:“!!0[] System.Array.Empty()”。
    好片
    分页插入
    linux查看ssl证书到期时间
    oracle复制表结构和表数据
    python的logging 模块的propagate设置
    【转载】 深究强化学习在谷歌芯片布局上的应用
    安全岗春招面经总结
    学历史有什么用——视频分享:學歷史的大用:呂世浩(ShihHao Lu) at TEDxTaipei 2014
  • 原文地址:https://www.cnblogs.com/bzzs/p/13141708.html
Copyright © 2020-2023  润新知