[BZOJ3282]LCT模板(单点修改,区间查询)

本文深入探讨了LCT树的基础概念与应用技巧,并通过一个具体的实战题目来讲解如何使用LCT树解决单点修改与区间查询的问题。文章提供了完整的代码实现及详细注释,帮助读者理解LCT树的操作流程。

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

题目:

我是超链接

题解:

这就是LCT的裸题啦,单点修改啦,区间查询xor啦,都是比较简单的操作
单点修改直接修改就好啦,然后access一下,从下面到上面的access最适合我们update值了,那就在access里面update几次?
区间查询在update里面搞点事情就行
后面有小总结啦

代码:

#include <cstdio>
#include <iostream>
using namespace std;
const int N=300005;
int ch[N][2],xo[N],delta[N],f[N],stack[N],key[N];
int get(int x){return ch[f[x]][1]==x;}
void updata(int x){xo[x]=xo[ch[x][0]]^xo[ch[x][1]]^key[x];}
void pushdown(int x)
{
    if(delta[x])
    {
        swap(ch[x][0],ch[x][1]);
        delta[ch[x][0]]^=1; delta[ch[x][1]]^=1;
        delta[x]=0;
    }
}
bool Is_root(int x){return ch[f[x]][0]!=x && ch[f[x]][1]!=x;}
void rotate(int x)
{
    int old=f[x],oldf=f[old],which=get(x),gen=Is_root(old);
    ch[old][which]=ch[x][which^1]; f[ch[x][which^1]]=old;
    f[old]=x; ch[x][which^1]=old;
    f[x]=oldf; if (!gen) ch[oldf][ch[oldf][1]==old]=x;
    updata(old);
    updata(x);
}
void splay(int x)
{
    int top=0,i;
    for (i=x;!Is_root(i);i=f[i]) stack[++top]=i;
    stack[++top]=i;
    for (i=top;i>=1;i--) pushdown(stack[i]);

    for (;!Is_root(x);rotate(x))
      if (!Is_root(f[x])) rotate(get(f[x])==get(x)?f[x]:x);
}
void access(int x)
{
    int t=0;
    for (;x;t=x,x=f[x])
    {
        splay(x);
        ch[x][1]=t;
        updata(x);
    }
}
void reverse(int x)
{
    access(x);
    splay(x);
    delta[x]^=1;
}
int find(int x)
{
    int now=x;
    while (ch[now][0]) now=ch[now][0];
    return now;
}
bool connect(int x,int y)
{
    access(x); splay(x);
    int fa1=find(x);
    access(y); splay(y);
    int fa2=find(y);
    if (fa1==fa2) return 1;
    return 0;
}
void Link(int x,int y)
{
    if (connect(x,y)) return;
    reverse(x);
    f[x]=y;
    splay(x);
}
void Cut(int x,int y)
{
    if (!connect(x,y)) return;
    reverse(x);
    access(y);
    splay(y);
    ch[y][0]=f[x]=0;
}
int qurry(int x,int y)
{
    reverse(x);
    access(y);
    splay(y);
    return xo[y];
}
int main()
{
    int n,m,i,id;
    scanf("%d%d",&n,&m);
    for (i=1;i<=n;i++) scanf("%d",&key[i]);
    while (m--)
    {
        int x,y;
        scanf("%d%d%d",&id,&x,&y);
        if (id==0) printf("%d\n",qurry(x,y));
        else if (id==1) Link(x,y);
        else if (id==2) Cut(x,y);
        else {key[x]=y; access(x);}
    }
}

tip:

在区间里查询值的做法:把一个端点reverse到根,然后把另一个端点access+splay到顶点,这时候顶点维护的值就是我们要的值,因为不属于这个区间内的点(也就是不属于这条链上的)根本就不是这棵splay的儿子,值根本不会被记录进去

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值