【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;
View Code

 

转载于:https://www.cnblogs.com/Damitu/p/8158291.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值