P3391【模板】文艺平衡树

本题主要学习

1,平衡树按照区间建树

int build(int l,int r,int fa){
    if(l>r){
        return 0;
    }
    int mid=(l+r)/2;
    int opt=++tot;
    tre[opt].ch[0]=tre[opt].ch[1]=0;
    tre[opt].fa=fa;
    tre[opt].cnt++;
    tre[opt].val=a[mid];
    tre[opt].siz++;
    tre[opt].ch[0]=build(l,mid-1,opt);
    tre[opt].ch[1]=build(mid+1,r,opt);
    update(opt);
    return opt;
}

2,平衡树tag维护

void update(int p){
    if(!p){
        return;
    }
    tre[p].siz=tre[p1].siz+tre[p2].siz+tre[p].cnt;
}

void pushdown(int p){
    if(p&&tre[p].tag){
        tre[p1].tag^=1;
        tre[p2].tag^=1;
        swap(tre[p].ch[0],tre[p].ch[1]);
        tre[p].tag=0;
    }
}

3,平衡树将点旋转至目标点

void splay(int x,int k){
    for(int f;(f=tre[x].fa)!=k;rotate(x)){
        if(tre[f].fa!=k){
            rotate(get(x)==get(f)?f:x);
        }
    }
    if(k==0){
        root=x;
    }
}

平衡树把点 l-1 转到顶端 r+1 转到 l-1 右儿子,即可保证 r-1 左儿子编号均为:l-1<i<r+1,最后把r+1 左儿子交换位置就完成了翻转

完整代码

#include<bits/stdc++.h>
#define p1 tre[p].ch[0]
#define p2 tre[p].ch[1]
using namespace std;
const int F=600000;

struct sl1{
    int l,r;
    int tag,val,cnt,siz,fa;
    int ch[2];
}tre[F];

int tot,n,m,root,top;
int a[F],sack[F];

int get(int x){
    return x==tre[tre[x].fa].ch[1];
}

void update(int p){
    if(!p){
        return;
    }
    tre[p].siz=tre[p1].siz+tre[p2].siz+tre[p].cnt;
}

void pushdown(int p){
    if(p&&tre[p].tag){
        tre[p1].tag^=1;
        tre[p2].tag^=1;
        swap(tre[p].ch[0],tre[p].ch[1]);
        tre[p].tag=0;
    }
}

int build(int l,int r,int fa){
    if(l>r){
        return 0;
    }
    int mid=(l+r)/2;
    int opt=++tot;
    tre[opt].ch[0]=tre[opt].ch[1]=0;
    tre[opt].fa=fa;
    tre[opt].cnt++;
    tre[opt].val=a[mid];
    tre[opt].siz++;
    tre[opt].ch[0]=build(l,mid-1,opt);
    tre[opt].ch[1]=build(mid+1,r,opt);
    update(opt);
    return opt;
}

/*inline void rotate(int x){
	int fnow=tre[x].fa,ffnow=tre[fnow].fa;
	pushdown(x),pushdown(fnow);
	bool w=get(x);
	tre[fnow].ch[w]=tre[x].ch[w^1];
	tre[tre[fnow].ch[w]].fa=fnow;
	tre[fnow].fa=x;
	tre[x].fa=ffnow;
	tre[x].ch[w^1]=fnow;
	if(ffnow){
		tre[ffnow].ch[tre[ffnow].ch[1]==fnow]=x;
	}
	update(fnow);
}*/

void rotate(int p){
    int y=tre[p].fa;
    int z=tre[y].fa;
    pushdown(p);
    pushdown(y);
    int chk=get(p);
    tre[y].ch[chk]=tre[p].ch[chk^1];
    if(tre[p].ch[chk^1]){
        tre[tre[p].ch[chk^1]].fa=y;
    }
    tre[p].ch[chk^1]=y;
    tre[y].fa=p;
    tre[p].fa=z;
    if(z){
        tre[z].ch[tre[z].ch[1]==y]=p;
    }
    update(p);
    update(y);
}

void splay(int x,int k){
    for(int f;(f=tre[x].fa)!=k;rotate(x)){
        if(tre[f].fa!=k){
            rotate(get(x)==get(f)?f:x);
        }
    }
    if(k==0){
        root=x;
    }
}

int find(int x){
    int p=root;
    while(1){
        pushdown(p);
        if(x<=tre[p1].siz){
            p=p1;
        }
        else{  
            x-=tre[p1].siz+1;
            if(!x){
                return p;
            }
            p=p2;
        }
    }
}

void dfs(int x){
    pushdown(x);
    if(tre[x].ch[0]){
        dfs(tre[x].ch[0]);
    }
    if(tre[x].val!=-F&&tre[x].val!=F){
        sack[++top]=tre[x].val;
    }
    if(tre[x].ch[1]){
        dfs(tre[x].ch[1]);
    }
}

void work(int x,int y){
    int l=x-1,r=y+1;
    int p3=find(l);
    int p4=find(r);
    splay(p3,0);
    splay(p4,p3);
    int opt=tre[root].ch[1];
    opt=tre[opt].ch[0];
    tre[opt].tag^=1;
}

int main(){
    cin>>n>>m;
    a[1]=-F;
    a[n+2]=F;
    for(int i=1;i<=n;i++){
        a[i+1]=i;
    }
    root=build(1,n+2,0);
    while(m--){
        int x,y;
        cin>>x>>y;
        work(x+1,y+1);
    }
    /*for(int i=1;i<=tot;i++){
        cout<<tre[i].val;
        cout<<":"<<tre[i].ch[0]<<" "<<tre[i].ch[1]<<endl;
    }*/
    dfs(root);
    for(int i=1;i<=top;i++){
        cout<<sack[i]<<" ";
    }
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值