题意
https://www.luogu.org/problemnew/show/P5292
思考
最朴素的想法,从可行的二元组(u,v)向外拓展,及u的出边所指的颜色与v的出边所指的颜色若相同,继续更新二元组(u',v'),复杂度约为O(m2)。
我们发现,很多时候边上的转移其实是没有必要的,因为有很多情况能转移到相同的字符串,因此我们要删去一些边,并且使得不改变原图的性质。
先考虑原图中边的两端颜色相同的边构成的连通块,若为二分图,则取其任意生成树;若不为二分图,则取其任意生成树,并添加一个自环。
二分图的意思,就是相同颜色段的长度只与奇偶性有关,当字符串另一端不断添加相同字符的同时,二分图中的字符可以不断地在A集合与B集合中转换。
两端颜色不同的边构成的连通块,也是取其任意生成树。
这样边数为O(n)级别,复杂度为O(n2)。
代码
1 // luogu-judger-enable-o2 2 #include<bits/stdc++.h> 3 using namespace std; 4 const int maxn=5E5+5; 5 int head[maxn*2],size,n,m,x,y,color[maxn],flag,q; 6 char c[maxn]; 7 bool f[5005][5005],can[maxn]; 8 struct edge{int from,to,next;}; 9 struct pt{int x,y;}; 10 queue<pt>Q; 11 struct graph 12 { 13 edge E[maxn*2]; 14 int head[maxn*2],size; 15 void add(int u,int v) 16 { 17 E[++size].to=v; 18 E[size].next=head[u]; 19 E[size].from=u; 20 head[u]=size; 21 } 22 }A,B,G; 23 void dfs1(int u,int now) 24 { 25 color[u]=now; 26 for(int i=A.head[u];i;i=A.E[i].next) 27 { 28 int v=A.E[i].to; 29 if(now==color[v])flag=1; 30 if(color[v])continue; 31 G.add(u,v); 32 G.add(v,u); 33 if(now==1)dfs1(v,2); 34 else dfs1(v,1); 35 } 36 } 37 void dfs2(int u) 38 { 39 color[u]=1; 40 for(int i=B.head[u];i;i=B.E[i].next) 41 { 42 int v=B.E[i].to; 43 if(color[v])continue; 44 G.add(u,v); 45 G.add(v,u); 46 dfs2(v); 47 } 48 } 49 void init1() 50 { 51 for(int i=1;i<=A.size;++i) 52 can[A.E[i].from]=can[A.E[i].to]=1; 53 for(int u=1;u<=n;++u) 54 { 55 if(color[u]||!can[u])continue; 56 flag=0; 57 dfs1(u,1); 58 if(flag)G.add(u,u); 59 } 60 } 61 void init2() 62 { 63 memset(color,0,sizeof(color)); 64 memset(can,0,sizeof(can)); 65 for(int i=1;i<=B.size;++i) 66 can[B.E[i].from]=can[B.E[i].to]=1; 67 for(int u=1;u<=n;++u) 68 { 69 if(color[u]||!can[u])continue; 70 dfs2(u); 71 } 72 } 73 void work() 74 { 75 while(!Q.empty()) 76 { 77 pt u=Q.front(); 78 Q.pop(); 79 for(int i=G.head[u.x];i;i=G.E[i].next) 80 { 81 for(int j=G.head[u.y];j;j=G.E[j].next) 82 { 83 int u=G.E[i].to,v=G.E[j].to; 84 if(c[u]==c[v]) 85 { 86 if(!f[u][v])Q.push((pt){u,v}); 87 f[u][v]=f[v][u]=1; 88 } 89 } 90 } 91 } 92 } 93 int main() 94 { 95 ios::sync_with_stdio(false); 96 cin>>n>>m>>q; 97 for(int i=1;i<=n;++i) 98 { 99 cin>>c[i]; 100 f[i][i]=1; 101 Q.push((pt){i,i}); 102 } 103 for(int i=1;i<=m;++i) 104 { 105 cin>>x>>y; 106 if(c[x]==c[y]) 107 { 108 A.add(x,y),A.add(y,x); 109 f[x][y]=f[y][x]=1; 110 Q.push((pt){x,y}); 111 } 112 else B.add(x,y),B.add(y,x); 113 } 114 init1(); 115 init2(); 116 work(); 117 for(int i=1;i<=q;++i) 118 { 119 cin>>x>>y; 120 if(f[x][y])cout<<"YES"<<endl; 121 else cout<<"NO"<<endl; 122 } 123 return 0; 124 }