uoj207 共价大爷游长沙

题意:动态树上支持加入路径、删除路径、询问一条边是否被当时存在的所有路径经过?

标程:

 1 #include<bits/stdc++.h>
 2 #define P pair<int,int>
 3 using namespace std;
 4 int read()
 5 {
 6     int x=0;char ch=getchar();
 7     while (ch<'0'||ch>'9') ch=getchar();
 8     while ('0'<=ch&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
 9     return x;
10 }
11 const int N=300005;
12 P e[N];
13 int son[N][2],fa[N],top,q[N],rev[N],sum[N],lsum[N],val[N],n,Q,x,y,op,w[N],u,v,cnt,s;
14 bool is_rt(int x){return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;}
15 void up(int x)
16 {
17     sum[x]=val[x]^lsum[x];
18     sum[x]^=sum[son[x][0]]^sum[son[x][1]]; 
19 }
20 void down(int x)
21 {
22     if (rev[x]) 
23     {
24         rev[son[x][0]]^=1;rev[son[x][1]]^=1;rev[x]^=1;
25         swap(son[x][0],son[x][1]);
26     }
27 }
28 void rot(int x)
29 {
30     int y=fa[x],z=fa[y],l=(son[y][1]==x),r=l^1;
31     if (!is_rt(y)) son[z][son[z][1]==y]=x;
32     fa[x]=z;fa[y]=x;fa[son[x][r]]=y;
33     son[y][l]=son[x][r];son[x][r]=y;
34     up(y);up(x);
35 }
36 void spl(int x)
37 {
38     q[top=1]=x;
39     for (int i=x;!is_rt(i);i=fa[i]) q[++top]=fa[i];
40     while (top) down(q[top--]);
41     for (int y;!is_rt(x);rot(x))//注意这里的y要在内部定义,否则会更改掉外面的y 
42     {
43         if (!is_rt(y=fa[x]))
44           rot(((son[y][0]==x)^(son[fa[y]][0]==y))?x:y); 
45     }
46 }
47 void accs(int x) {
48     for (int t=0;x;t=x,x=fa[x]) 
49     {
50         spl(x);
51         lsum[x]^=sum[son[x][1]];//原来的重儿子变成轻儿子,加入 
52         lsum[x]^=sum[son[x][1]=t];//去掉原来的轻儿子 
53         up(x);    
54     }
55 }
56 void make_rt(int x) {accs(x);spl(x);rev[x]^=1;}
57 void cut(int x,int y){make_rt(x);accs(y);spl(y);fa[x]=son[y][0]=0;up(y);}
58 void link(int x,int y){make_rt(x);fa[x]=y;make_rt(y);lsum[y]^=sum[x];up(y);}
59 void mdi(int x,int v) {make_rt(x);val[x]^=v;up(x);}
60 int main()
61 {
62     int id=read();srand(time(NULL));
63     n=read();Q=read();
64     for (int i=1;i<n;i++) u=read(),v=read(),link(u,v);
65     while (Q--)
66     {
67         op=read();
68         if (op==1)
69         {
70             x=read();y=read();cut(x,y);
71             x=read();y=read();link(x,y); 
72         }else if (op==2){
73             x=read();y=read();w[++cnt]=rand()*131;
74             mdi(x,w[cnt]);mdi(y,w[cnt]);
75             s^=w[cnt];e[cnt]=P(x,y);
76         }else if (op==3) {
77             x=read();s^=w[x];
78             mdi(e[x].first,w[x]);mdi(e[x].second,w[x]);
79         }
80         else {
81             x=read();y=read();
82             make_rt(x);accs(y);spl(y);
83             puts(sum[x]==s?"YES":"NO");
84         }
85     }
86     return 0;
87 } 
View Code

题解:lct+随机权值

对每条路径随机一个权值,并在两端点处赋值。

询问时如果子树中的权值异或和=所有路径的异或和,那么大概率(x,y)这条边被所有路径经过。

sum表示整个子树的异或和,lsum表示轻儿子子树的异或和。由于重儿子在lct上会不断改变,而lsum只有在accs重连和link时会被改变。

link时修改lsum[y],需要make_rt(y),不然需要改变y到根的链上所有点的sum。

猜你喜欢

转载自www.cnblogs.com/Scx117/p/9144609.html