C07【模板】P3690 动态树(Link Cut Tree)

视频链接:265【模板】P3690 动态树(Link Cut Tree)_哔哩哔哩_bilibili

 

 

 

 

 

 

 

 

 

Luogu P3690 【模板】动态树(Link Cut Tree)

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

#define N 100010
#define fa(x) tr[x].fa
#define lc(x) tr[x].ch[0]
#define rc(x) tr[x].ch[1]
#define notroot(x) lc(fa(x))==x||rc(fa(x))==x
int n,m;
struct node{ //splay的信息
  int ch[2],fa,v,sum;
  int tag; //翻转懒标记
}tr[N]; 

void pushup(int x){ //上传
  tr[x].sum=tr[lc(x)].sum^tr[x].v^tr[rc(x)].sum;
}
void pushdown(int x){ //下传
  if(tr[x].tag){
    swap(lc(x),rc(x));
    tr[lc(x)].tag^=1;
    tr[rc(x)].tag^=1;
    tr[x].tag=0;
  }
}
void pushall(int x){ //递归下传
  if(notroot(x)) pushall(fa(x));
  pushdown(x);
}
void rotate(int x){ //旋转x
  int y=fa(x),z=fa(y),k=rc(y)==x; //y的右儿是x
  if(notroot(y)) tr[z].ch[rc(z)==y]=x; fa(x)=z; //z的儿是x,x的父是z
  tr[y].ch[k]=tr[x].ch[k^1]; fa(tr[x].ch[k^1])=y; //y的儿是x的异儿,x的异儿的父是y
  tr[x].ch[k^1]=y; fa(y)=x; //x的异儿是y,y的父是x
  pushup(y); pushup(x); //自底向上pushup
}
void splay(int x){ //x伸展到根
  pushall(x); //递归下传
  while(notroot(x)){ //折线转xx,直线转yx
    int y=fa(x),z=fa(y);
    if(notroot(y)) (rc(y)==x)^(rc(z)==y)?rotate(x):rotate(y);
    rotate(x);
  }
}
void access(int x){ //打通x到树根的路
  for(int y=0; x;){
    splay(x); //x转到当前splay的根
    rc(x)=y;  //x的右儿指向下面splay的根
    pushup(x); //更新x的sum
    y=x,x=fa(x); //存x,x爬到上面的splay
  }
}
void makeroot(int x){ //换根
  access(x); //通路
  splay(x);  //伸展
  tr[x].tag^=1; //翻转懒标记
}
void split(int x,int y){ //分离x到y的路径
  makeroot(x); //x换根
  access(y); //y通路
  splay(y);  //y伸展
}
void output(int x,int y){ //输出
  split(x,y); //分离
  printf("%d\n",tr[y].sum);
}
int findroot(int x){ //找根
  access(x);
  splay(x);
  while(lc(x)) pushdown(x),x=lc(x);
  splay(x); //防止卡链
  return x;
}
void link(int x,int y){ //连边
  makeroot(x);
  if(findroot(y)!=x) fa(x)=y;
}
void cut(int x,int y){ //断边
  makeroot(x);
  if(findroot(y)==x&&fa(y)==x&&!lc(y))
    fa(y)=0, pushup(x);
}
void change(int x,int y){ //修改
  splay(x);
  tr[x].v=y;
  pushup(x);
}
int main(){
  scanf("%d%d",&n,&m); int t,x,y;
  for(int i=1; i<=n; i++)scanf("%d",&tr[i].v);
  while(m--){
    scanf("%d%d%d",&t,&x,&y);
    if(t==0) output(x,y);
    else if(t==1) link(x,y);
    else if(t==2) cut(x,y);
    else change(x,y);
  }
}

 

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

#define N 100010
#define lc(x) ch[x][0]
#define rc(x) ch[x][1]
#define notroot(x) lc(fa[x])==x||rc(fa[x])==x
int n,m;
int ch[N][2],fa[N],v[N],sum[N],tag[N];
//splay:ch儿,fa父,v点权,sum异或和,tag翻转懒标记

void pushup(int x){ //上传
  sum[x]=sum[lc(x)]^v[x]^sum[rc(x)];
}
void pushdown(int x){ //下传
  if(tag[x]){
    swap(lc(x),rc(x));
    tag[lc(x)]^=1;
    tag[rc(x)]^=1;
    tag[x]=0;
  }
}
void pushall(int x){ //递归下传
  if(notroot(x)) pushall(fa[x]);
  pushdown(x);
}
void rotate(int x){ //旋转x
  int y=fa[x],z=fa[y],k=rc(y)==x; //y的右儿是x吗
  if(notroot(y)) ch[z][rc(z)==y]=x; fa[x]=z; //z的儿是x,x的父是z
  ch[y][k]=ch[x][k^1]; fa[ch[x][k^1]]=y; //y的儿是x的异儿,x的异儿的父是y
  ch[x][k^1]=y; fa[y]=x; //x的异儿是y,y的父是x
  pushup(y); pushup(x); //自底向上pushup
}
void splay(int x){ //x伸展到根
  pushall(x); //递归下传
  while(notroot(x)){ //折线转xx,直线转yx
    int y=fa[x],z=fa[y];
    if(notroot(y)) (rc(y)==x)^(rc(z)==y)?rotate(x):rotate(y);
    rotate(x);
  }
}
void access(int x){ //打通x到树根的路
  for(int y=0; x;){
    splay(x); //x转到当前splay的根
    rc(x)=y;  //x的右儿指向下面splay的根
    pushup(x); //更新x的sum
    x=fa[y=x]; //把x给y,x爬到上面的splay
  }
}
void makeroot(int x){ //换根
  access(x); //通路
  splay(x);  //伸展
  tag[x]^=1; //翻转懒标记
}
void split(int x,int y){ //分离x到y的路径
  makeroot(x); //x换根
  access(y);   //y通路
  splay(y);    //y伸展
}
void output(int x,int y){ //输出
  split(x,y); //分离
  printf("%d\n",sum[y]);
}
int findroot(int x){ //找根
  access(x); //通路
  splay(x);  //伸展
  while(lc(x)) pushdown(x),x=lc(x);
  splay(x);  //防止卡链
  return x;
}
void link(int x,int y){ //连边
  makeroot(x); //x换根
  if(findroot(y)!=x) fa[x]=y;
}
void cut(int x,int y){ //断边
  makeroot(x); //x换根
  if(findroot(y)==x&&fa[y]==x&&!lc(y))
    fa[y]=0, pushup(x);
}
void change(int x,int y){ //修改
  splay(x); //伸展
  v[x]=y;
  pushup(x);
}
int main(){
  scanf("%d%d",&n,&m); int t,x,y;
  for(int i=1; i<=n; i++)scanf("%d",&v[i]);
  while(m--){
    scanf("%d%d%d",&t,&x,&y);
    if(t==0) output(x,y);
    else if(t==1) link(x,y);
    else if(t==2) cut(x,y);
    else change(x,y);
  }
}

 

posted @ 2022-07-31 19:37  董晓  阅读(715)  评论(0编辑  收藏  举报