【2017.12.22.A】
A
题面:
给一个n个点m条边的无向图,你可以选择一个点作为起点,然后沿着图中的边开始走,走的过程中,同一条边不能经过两次(相反的方向也不行)。最后你要回到起点。假设你走了x条边,有两个问题:
Q1:x 是否可以为奇数?
Q2:x 是否可以为偶数?
输入:
第一行读入两个数 n 和 m,分别表示图的点数和边数。
接下来m行,每行两个整数ui, vi,表示ui和vi之间有一条边。
保证不会有自环和重边。
输出:
输出两行,第一行输出YES或NO,表示第一个问题的答案,第二行输出YES或NO,表示第二个问题的答案。
样例输入1:
1 0
样例输出2:
NO
NO
样例输入2:
3 3
1 2
2 3
3 1
样例输出2:
YES
NO
样例输入3:
4 4
1 2
2 3
3 4
4 1
样例输出3:
NO
YES
数据范围:
对于20%的数据,1 <= n <= 30, 1 <= m <= 50
对于50%的数据,1 <= n <= 1000, 1 <= m <= 3000
对于100%的数据,1 <= n <= 100000, 1 <= m <= 300000, 1 <= ui, vi <= n
【题解】
①对于我们的图走啊走你会发现这样一件事:
若一个点只在一个奇环或偶环中,那么从它出发必定只能走出奇或偶;
若一个点只在多个奇环中 或者 在奇环和偶环中,那么从它出发奇偶都可以走;
若一个点只在多个偶环中,那么从它出发只能走出偶;(奇偶都指边数)
②考虑记下每个点被多少个奇环和偶环覆盖dfs+差分即可;(如果不是很清楚可以百度树上差分)
注意差分的技巧性(因标记边,点而异,此处为标记点):
1 /*5 6 2 1 2 3 2 3 4 1 3 5 3 4 6 4 5 7 3 5 8 在下面自己测wa得一塌糊涂,交到cena就AC了; 9 我还搞了两个多小时; 10 只要有有漏洞的C++在,就没有上帝。。 11 记住树上差分的基本思想。(不过我现在还不知道染色到底有没有理) 12 */ 13 #include <cstdio> 14 #include <iostream> 15 #include <cstring> 16 #include <algorithm> 17 #include <queue> 18 #include <vector> 19 #include <ctime> 20 #include <cmath> 21 #define inf 0x3f3f3f3f 22 #define ll long long 23 #define N 100100 24 #define M 300100 25 #define mem(f,a) memset(f,a,sizeof(f)) 26 #define Run(i,l,r) for(int i=l;i<=r;i++) 27 #define Don(i,l,r) for(int i=l;i>=r;i--) 28 #define Eun(i,u,hd,E) for(int i=hd[u],v=E[i].v;i!=-1;i=E[i].next,v=E[i].v) 29 using namespace std; 30 struct Edge{ 31 int u,v,next; 32 }E[2*M],e[M]; 33 int n,m; 34 int k1,k2,hd1[N],hd2[N],fg1,fg2; 35 int c1[N],c2[N],p[N][20],d[N],vis[2*M],idx,f[N]; 36 void adde1(int u,int v) 37 { E[k1]=(Edge){u,v,hd1[u]}; 38 hd1[u]=k1++; 39 } 40 void adde2(int u,int v) 41 { e[k2]=(Edge){u,v,hd2[u]}; 42 hd2[u]=k2++; 43 } 44 int find(int x) 45 { if (f[x]==x) return x; 46 return f[x]=find(f[x]); 47 } 48 void Dfs(int u,int fa) 49 { p[u][0]=fa; d[u]=d[fa]+1; 50 Run(i,1,20){ 51 if ((1<<i)>d[u]) break; 52 p[u][i]=p[p[u][i-1]][i-1]; 53 } 54 Eun(i,u,hd2,e) Dfs(v,u); 55 } 56 int LCA(int a,int b) 57 { if (d[a]>d[b]) swap(a,b); 58 Don(i,20,0) if (d[a]<=d[b]-(1<<i)) b=p[b][i]; 59 if (a==b) return a; 60 Don(i,20,0) if (p[a][i]!=p[b][i]) a=p[a][i],b=p[b][i]; 61 return p[a][0]; 62 } 63 void update(int u,int v) 64 { int t=LCA(u,v); 65 if ((d[v]+d[u]-2*d[t]+1)&1) c1[t]--,c1[p[t][0]]--,c1[u]++,c1[v]++; 66 else c2[t]--,c2[p[t][0]]--,c2[u]++,c2[v]++; 67 } 68 void dfs1(int u,int fa) 69 { int fu=find(u); 70 Eun(i,u,hd1,E){ 71 int fv=find(v); 72 if (v==fa) vis[i]=1; 73 if (fu==fv) continue; 74 vis[i]=1;adde2(u,v);f[fv]=fu; 75 dfs1(v,u); 76 } 77 } 78 void dfs2(int u) 79 { Eun(i,u,hd2,e) dfs2(v),c1[u]+=c1[v],c2[u]+=c2[v]; 80 fg1|=c1[u]; fg2|=c2[u]; 81 if (c1[u]>1) fg2=1; 82 } 83 int main() 84 { freopen("A.in","r",stdin); 85 //freopen("A.out","w",stdout); 86 scanf("%d%d",&n,&m); 87 mem(hd1,-1); mem(hd2,-1); 88 Run(i,1,m){ 89 int u,v; 90 scanf("%d%d",&u,&v); 91 adde1(u,v);adde1(v,u); 92 } 93 Run(i,1,n) f[i]=i; 94 Run(i,1,n) if (f[i]==i) dfs1(i,0); //建树 95 Run(i,1,n) if (f[i]==i) Dfs(i,0); //LCA预处理 96 Run(i,0,2*m-1) if (!vis[i]) update(E[i].u,E[i].v),vis[i^1]=1; 97 Run(i,1,n) if (f[i]==i) dfs2(i); //差分 98 if (fg1) printf("YES\n"); else printf("NO\n"); 99 if (fg2) printf("YES\n"); else printf("NO\n"); 100 return 0; 101 }//by tkys_Austin;