bzoj3282(Tree lct模板)

本文深入探讨了LCT树(Lazy Cascading Tree)的数据结构原理及其在算法竞赛中的应用。作者通过分享自己AC一道LCT题目过程中的疑惑与探索,详细解释了LCT树的插入、删除、查找等操作实现细节,包括如何通过旋转和路径压缩来保持树的平衡,以及如何使用懒惰标记提高效率。此外,还提供了完整的C++代码示例,帮助读者更好地理解和实践LCT树。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目
在这里插入图片描述
虽然代码ac了。由于不太清楚原理。。模模糊糊的。。找了网上好几个代码对拍一下每份之间都不一样。。emmm。。第一道lct很难受,不知道以后写题的过程需不需要了解这么清原理。
其实感觉我也懂一丢丢原理嘻嘻嘻。。。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<map>
#define m(a,b) memset(a,b,sizeof a)
using namespace std;
const int N=3e5+5;
int f[N],ch[N][2],val[N],sum[N],st[N],tag[N];
map<int,int>mp[N];
inline void pushup(int x){
    sum[x]=sum[ch[x][0]]^sum[ch[x][1]]^val[x];
}
inline void pushdown(int x){
    if(!tag[x]) return;
    swap(ch[ch[x][0]][0],ch[ch[x][0]][1]),tag[ch[x][0]]^=1;
    swap(ch[ch[x][1]][0],ch[ch[x][1]][1]),tag[ch[x][1]]^=1;
    tag[x]=0;
}
inline int notroot(int x){//不是当前所在splay的根
    return ch[f[x]][0]==x||ch[f[x]][1]==x;
}
inline void route(int x){
    int y=f[x],z=f[y],w=(ch[y][1]==x);
    if(notroot(y)) ch[z][ch[z][1]==y]=x;//先这句话!!!
    f[x]=z;
    ch[y][w]=ch[x][w^1];if(ch[y][w]) f[ch[y][w]]=y;
    ch[x][w^1]=y,f[y]=x;
    pushup(y),pushup(x);
}
inline void splay(int x){
    int y=x,num=0;st[++num]=y;
    while(notroot(y)) st[++num]=(y=f[y]);
    while(num) pushdown(st[num--]);
    if(!notroot(x)) return;
    for(int fa=f[x];notroot(x);route(x),fa=f[x])
        if(notroot(fa)) ((ch[fa][1]==x)^(ch[f[fa]][1]==fa))?route(x):route(fa);
}
inline void access(int x){
    for(int y=0;x;x=f[y=x])
        splay(x),ch[x][1]=y,pushup(x);//一定要有pushup 
}
inline void makeroot(int x){
    access(x),splay(x);
    swap(ch[x][0],ch[x][1]),tag[x]^=1;
}
inline int findroot(int x){//整颗联通树的根
    access(x),splay(x);
    while(ch[x][0]) pushdown(x),x=ch[x][0];
    splay(x);
    return x;
}
inline void split(int x,int y){//假如x-y这条边存在且处于一个splay中,那access(y)时 y就成了这颗splay的根哇。
    makeroot(x);access(y),splay(y);//个人觉得需要以y为根把。。因为access不小心就splay成了根?? 
}
inline void link(int x,int y){
    makeroot(x);//将x作为这颗联通树的根 而且也是这颗splay的root
    if(findroot(y)!=x) f[x]=y;//将两颗联通树连起来
}
inline void cut(int x,int y){
    if(!mp[x][y]) return;
    makeroot(x);//x为根了 x就是这棵树深度最小的了
    if(findroot(y)==x&&f[y]==x&&!ch[y][0]&&!ch[y][1])
        f[y]=ch[x][1]=0,pushup(x);
}
int main()
{
    int n,m;scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i) scanf("%d",&val[i]);
    while(m--){
        int f,x,y;scanf("%d%d%d",&f,&x,&y);
        switch(f){
            case 0:split(x,y);printf("%d\n",sum[y]);break;
            case 1:link(x,y);mp[x][y]=mp[y][x]=1;break;
            case 2:cut(x,y);break;
            case 3:splay(x);val[x]=y;//一定要将x置于其所在splay的root处,觉着直接这样就行了呀,反正当前这个splay的信息都是对的,而且我们的sum维护的当然没有跨树的呀
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值