[HNOI2019]校园旅行

题意

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 }
View Code

猜你喜欢

转载自www.cnblogs.com/GreenDuck/p/10710072.html
今日推荐