选择 (动态树)

Posted GFY

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了选择 (动态树)相关的知识,希望对你有一定的参考价值。

题目描述:

现在,我想知道自己是否还有选择。

给定n个点m条边的无向图以及顺序发生的q个事件。

每个事件都属于下面两种之一:

1、删除某一条图上仍存在的边

2、询问是否存在两条边不相交的路径可以从点u出发到点v

输入:

第一行三个整数n,m,q

接下来m行,每行两个整数u,v,表示u和v之间有一条边

接下来q行,每行一个大写字母o和2个整数u、v,依次表示按顺序发生的q个事件:

当o为’Z’时,表示删除一条u和v之间的边

当o为’P’时,表示询问是否存在两条边不相交的路径可以从点u出发到点v

输出:

对于每组询问,如果存在,输出Yes,否则输出No

样例输入:

7 8 7

1 2

1 3

1 4

2 3

3 4

3 7

7 4

5 6

Z 1 4

P 1 3

P 2 4

Z 1 3

P 1 3

Z 6 5

P 5 6

 

样例输出:

Yes

Yes

No

No

 

数据规模和约定:

对于20%的数据,max(n,m,q)<=100

对于全部数据,max(n,m,q)<=100000

思路:离线做,用动态树维护连通性,对于已经在同一个连通分块里面的两个点,将这两个点之间的所有点全部缩成一个点,这个点就是最上边的那个,也就是split(x,y)以后的y,然后询问的时候,倒着做,拆边变成加边,对于两个询问点,询问他们是不是在同一个缩的点内,如果是,那么他们就有两条边不相交的路线。

  1 #include<algorithm>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<iostream>
  6 #include<map>
  7 struct edge{
  8     int u,v,id;
  9 }e[200005],ask[200005];
 10 std::map<int,std::map<int,int> >mp;
 11 int n,m,q,ts[500005],tx[500005];
 12 int ch[200005][2],fa[200005],f[200005],st[200005],rev[200005],ans[200005];
 13 int read(){
 14     char ch=getchar();int t=0,ff=1;
 15     while (ch<0||ch>9){if (ch==-) ff=-1;ch=getchar();}
 16     while (0<=ch&&ch<=9){t=t*10+ch-0;ch=getchar();}
 17     return t*ff;
 18 }
 19 int Find(int x){
 20     int top=0,i;
 21     if (x==f[x]) return x;
 22     for (i=x;f[i]!=i;i=f[i]){
 23         ts[++top]=i;
 24     }
 25     int key=i;
 26     for (int i=top;i>=1;i--)
 27      f[ts[i]]=key;
 28     return key; 
 29 }
 30 bool isroot(int x){
 31     fa[x]=Find(fa[x]);
 32     return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;
 33 }
 34 void updata(int x){}
 35 void pushdown(int x){
 36     int l=ch[x][0],r=ch[x][1];
 37     if (rev[x]){
 38         rev[x]^=1;
 39         rev[l]^=1;rev[r]^=1;
 40         std::swap(ch[x][0],ch[x][1]);
 41     }
 42 }
 43 void rotate(int x){
 44     int y=fa[x],z=fa[y],l,r;
 45     if (ch[y][0]==x) l=0;else l=1;r=l^1;
 46     if (!isroot(y)){
 47         if (ch[z][0]==y) ch[z][0]=x;else ch[z][1]=x;
 48     }
 49     fa[x]=z;fa[y]=x;fa[ch[x][r]]=y;
 50     ch[y][l]=ch[x][r];ch[x][r]=y;
 51     updata(y);updata(x);
 52 }
 53 void splay(int x){
 54     int top=0;st[++top]=x;
 55     for (int i=x;!isroot(i);i=fa[i]){
 56         st[++top]=fa[i];
 57     }
 58     for (int i=top;i>=1;i--) pushdown(st[i]);
 59     while (!isroot(x)){
 60         int y=fa[x],z=fa[y];
 61         if (!isroot(y)){
 62             if (ch[y][0]==x^ch[z][0]==y) rotate(x);
 63             else rotate(y);
 64         }
 65         rotate(x);
 66     }
 67 }
 68 void access(int x){
 69     for (int t=0;x;t=x,fa[x]=Find(fa[x]),x=fa[x]){
 70         splay(x);
 71         ch[x][1]=t;
 72         updata(x);
 73     }
 74 }
 75 int find(int x){
 76     access(x);splay(x);
 77     while (ch[x][0]) x=ch[x][0];
 78     return x;
 79 }
 80 void makeroot(int x){
 81     access(x);splay(x);rev[x]^=1;
 82 }
 83 void split(int x,int y){
 84     makeroot(x);access(y);splay(y);
 85 }
 86 void bfs(int x){
 87     int h=1,t=1;tx[h]=x;
 88     for (;h<=t;h++){
 89         if (ch[tx[h]][0]) tx[++t]=ch[tx[h]][0];
 90         if (ch[tx[h]][1]) tx[++t]=ch[tx[h]][1];
 91     }
 92     for (int i=1;i<=t;i++){
 93         if (i!=1) fa[tx[i]]=0;
 94         f[tx[i]]=x;ch[tx[i]][0]=ch[tx[i]][1]=0;
 95     }
 96 }
 97 void link(int x,int y){
 98     x=Find(x);y=Find(y);
 99     if (find(x)!=find(y)){
100         makeroot(x);
101         fa[x]=y;
102     }else{
103         split(x,y);
104         bfs(y);
105     }
106 }
107 int main(){
108     n=read();m=read();q=read();
109     for (int i=1;i<=n;i++) f[i]=i;
110     for (int i=1;i<=m;i++){
111         e[i].u=read();e[i].v=read();
112         if (e[i].u>e[i].v) std::swap(e[i].u,e[i].v);
113         mp[e[i].u][e[i].v]++;
114     }
115     char opt[2];
116     for (int i=1;i<=q;i++){
117         scanf("%s",opt+1);
118         if (opt[1]==Z) ask[i].id=1;
119         else ask[i].id=2;
120         ask[i].u=read();ask[i].v=read();
121         if (ask[i].u>ask[i].v) std::swap(ask[i].u,ask[i].v);
122         if (ask[i].id==2) continue;
123         if (mp[ask[i].u][ask[i].v]>0) mp[ask[i].u][ask[i].v]--;
124         else ask[i].id=0;
125     }
126     for (int i=1;i<=m;i++)
127      if (mp[e[i].u][e[i].v]>0){
128             link(e[i].u,e[i].v);
129      }
130     for (int i=q;i>=1;i--)
131      if (ask[i].id==1){
132             link(ask[i].u,ask[i].v);
133      }else
134      if (ask[i].id==2)
135      {
136             if (Find(ask[i].u)!=Find(ask[i].v)) ans[i]=2;
137             else ans[i]=1;
138      }
139     for (int i=1;i<=q;i++)
140      if (ask[i].id==2){
141             if (ans[i]==1) puts("Yes");
142             else puts("No");
143      }
144 }

 

以上是关于选择 (动态树)的主要内容,如果未能解决你的问题,请参考以下文章

codevs 3981 动态最大子段和(线段树)

震波——动态点分治+线段树

P3939 数颜色 动态开点线段树

LuoguP3690 模板Link Cut Tree (动态树) LCT模板

luoguP3690 模板Link Cut Tree (动态树)[LCT]

AcWing 1264. 动态求连续区间和(线段树区间查询模板)