GotoAndPlay

10月3日,在杭州市西湖景区,一只小松鼠不停地接受一道道食物,花生、
玉米、饼干,可谓来者不拒,憨态可掬的模样吸引了众多围观者...
Description  
 小松鼠终于吃撑了,她决定逃离这个地方。
 我们用一张连通图来表示整个西湖的范围,每棵容小松鼠逗留的树都用
这张图上的一个点来表示。小松鼠能够通过只跳一次互相到达的两棵树用
图上的一条无向边来连接。
 吃撑了的小松鼠有些神志不清,每次她连跳两条边之后才会在到达的那
个点上休息。她想知道,是否存在一种连续的跳法,使得她有机会在所有
的树上都休息至少一次。
 对于这种跳法,你可以任选起点,允许重复经过边,允许重复经过点。
 但是超萌小松鼠是一只有梦想的小松鼠,她有时能够突破自己的极限,
使一些原本无法互相到达的两个点能够通过一次跳跃互相到达。
Input  
 第一行两个数n,m。n表示点的个数,m表示边的条数
 接下来m行,每行两个数x i ,y i ,表示x i 和y i 之间能够通过一次跳跃互相到
达。
 接下来一行一个数q,表示询问的个数。
 接下来q行,其中的第i行每行两个数a i ,b i 。表示在原图的基础上加上从a i 到b i 的
边。即成为一张n个点m + 1条边的图。
 保证给出的原图是个连通图,1 <= a i , b i , x i , y i <= n。
Output  
 输出一共q行,对于第i个询问,当在原图的基础上加上a i 与b i 间的无向边
后,如果小松鼠能够找到一种连续的跳法,使得她有机会在所有的树上至
少休息一次,输出一行“Yes”,否则输出一行“No” 。 (不包含引号)
Constraints  
 对于前50%,n, q <= 10 3 , m <= 2 × 10 3 。
 对于100%,n, q <= 10 5 , m <= 2 × 10 5 。

样例输入:

2 1
1 2
2
1 1  
1 2

样例输出:

Yes
No

黑白染色,从一开始黑白染色,显然颜色相同就能从一个到另一个休息

那么我们发现两个相邻节点颜色相同,就说明黑白互通了,那么说明可以输出Yes

满足以上条件则flag=1

如果flag=0且a的颜色不等于b则输出No

这里给出原题题解参考:

%%%%%YZD  OTZ

考虑如果给出的图是二分图,那么我们任定起点,无论跳跃多少次始终只能到达与起点在同一边的点,对于>1个点的连通图而言,显然是有点不能够“休息”到的。

考虑如果给出的图不是二分图,那么图内必然存在奇环。就算除该奇环外的部分属于二分图,只要在其中的某一边的所有点上休息过后,在奇环上绕一圈再出去就能够到达另一边的点。因此能够达到目标。

我们把回答转化成二分图的判定之后,再来考虑询问如何处理。

首先最暴力的做法是每次读入一条边之后和原图一起再做一次二分图判定。

由于每次都是在原图的基础上加一条边的,所以每次对于原图部分的判定显得尤其浪费。我们可以往保留原图信息的方向考虑这个问题。

我们对原图进行二分图染色,如果它不是二分图,那么加入任何边都不可能使它重新变回二分图,因此只要输出q个“Yes”即可。

接下来我们所讨论的都是原图是二分图的情况。

我们考虑读进来的一条边(x, y),如果xy在原图上属于同一种颜色,那么加上这条边相当于在二分图的同侧点间加了一条边,破坏了二分图的性质,因此输出“Yes”

否则如果属于不同的颜色,相当于在二分图的两侧间连了一条边,它还是个二分图,因此输出“No”

这样的方法刚开始可以用Bfs预处理,每次回答询问是O(1)

因此时间复杂度为O(m + q)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 struct Node
 7 {
 8   int next,to;
 9 }edge[400001];
10 int num,head[100001],n,m,q,vis[100001];
11 bool flag;
12 void add(int u,int v)
13 {
14   num++;
15   edge[num].next=head[u];
16   head[u]=num;
17   edge[num].to=v;
18 }
19 void dfs(int x)
20 {int i;
21   for (i=head[x];i;i=edge[i].next)
22     {
23       int v=edge[i].to;
24       if (vis[v]==0)
25     {
26       if (vis[x]==1)
27         vis[v]=2;
28       else vis[v]=1;
29       dfs(v);
30     }
31       else
32     {
33       if (vis[x]==vis[v])
34         {
35           flag=1;
36         }
37     }
38     }
39 }
40 int main()
41 {int i,x,y;
42   cin>>n>>m;
43   for (i=1;i<=m;i++)
44     {
45       scanf("%d%d",&x,&y);
46       add(x,y);add(y,x);
47     }
48   vis[x]=1;
49   dfs(1);
50   cin>>q;
51   while (q--)
52     {
53       scanf("%d%d",&x,&y);
54       if (vis[x]==vis[y])
55     {
56       printf("Yes
");
57     }
58       else if (flag) printf("Yes
");
59       else printf("No
");
60     }
61 }
原文地址:https://www.cnblogs.com/Y-E-T-I/p/7526430.html