namespace LCT
{
/*
这个模板是单点修改点权,然后询问x到y的异或和
*/
int fa[maxn];
int son[maxn][2];
int s[maxn];
int v[maxn];
int st[maxn];
bool fl[maxn];
inline bool isroot(int num)//如果返回True,就不是根结点
{
return son[fa[num]][0]==num||son[fa[num]][1]==num;
}
inline void pushup(int num)//向上更新,更新val
{
s[num]=s[son[num][0]]^s[son[num][1]]^v[num];
}
inline void rever(int num)//交换当前结点的子儿子
{
swap(son[num][0],son[num][1]);
fl[num]^=1;
}
inline void pushdown(int num)//向下更新lazy标记
{
if(fl[num])
{
if(son[num][0])rever(son[num][0]);
if(son[num][1])rever(son[num][1]);
fl[num]=0;
}
}
inline void rotate(int x)//splay向上换结点
{
int y=fa[x],z=fa[y],k=son[y][1]==x,w=son[x][!k];
if(isroot(y))son[z][son[z][1]==y]=x;son[x][!k]=y;son[y][k]=w;
if(w)fa[w]=y;fa[y]=x;fa[x]=z;
pushup(y);
}
inline void splay(int x){//只传了一个参数,因为所有操作的目标都是该Splay的根(与普通Splay的区别3)
int y=x,z=0;
st[++z]=y;//st为栈,暂存当前点到根的整条路径,pushdown时一定要从上往下放标记(与普通Splay的区别4)
while(isroot(y))st[++z]=y=fa[y];
while(z)pushdown(st[z--]);
while(isroot(x)){
y=fa[x];z=fa[y];
if(isroot(y))
rotate((son[y][0]==x)^(son[z][0]==y)?x:y);
rotate(x);
}
pushup(x);
}
inline void access(int num)//将num和根节点连一条实边
{
for(int y=0;num;num=fa[y=num])
{
splay(num);
son[num][1]=y;
pushup(num);
}
}
inline void makeroot(int num)//换根
{
access(num);
splay(num);
rever(num);
}
int findroot(int x)//找实际树上的根
{
access(x);
splay(x);
while(son[x][0])pushdown(x),x=son[x][0];
splay(x);
return x;
}
inline void split(int x,int y)//将x和y连一条实边链
{
makeroot(x);
access(y);
splay(y);
}
inline void link(int x,int y)//将x和y连接(树上的连接)
{
makeroot(x);
if(findroot(y)!=x)fa[x]=y;
}
inline void cut(int x,int y)//将x和y断开(树上的断开),可以判断是否存在这条边
{
makeroot(x);
if(findroot(y)==x&&fa[y]==x&&!son[y][0])
{
fa[y]=son[x][1]=0;
pushup(x);
}
}
}
LCT模板
最新推荐文章于 2022-11-02 11:23:29 发布