• CF19E Fairy(树上差分)


    题目描述

    很久很久以前,有一个仙女叫做A。有一天一个少年B找到她,并且请求她预测他的未来。仙女看着她的水晶球,说这位少年不久将遇见世界上最美丽的公主,并且将迎娶她为妻。然后仙女在一张纸上画了n个点,并把它们分为几个板块,每个板块以一些点为始,另一些点为终。画完这幅画,仙女要求少年擦掉之上的一个板块。然后她尝试给每个点画上红色或蓝色,让纸上没有板块有和它的结尾颜色一样的点。如果她能做到,这个预言将会成真。B想邂逅世界上最美丽的公主,所以他想要你帮助他。找到所有能帮助他邂逅公主的板块。

    输入输出格式:

    输入格式:

    输入文件的第一行有两个整数:n——点数;m:板块个数。

    接下来的m行有板块的描述。每一个描述有两个整数,用空格隔开——v,u——各点的编号(index),由此板块连接。没有板块在描述中会被描述两次。

    输出格式:

    输出文件的第一行输出数字k——答案中板块的数量。输出文件的第二行输出k个数字,以空格隔开————每个板块的编号,升序排列。每个编号只应被输出一次。板块从1开始编号,以输入的顺序为序。

    题解

    因为二分图没有奇环,我们就把奇环删掉就行了。

    实际上需要分情况讨论:

    当没有奇环时,随便删掉一条边即可。

    当只有一个奇环时,删掉这个奇环上没有被偶环覆盖的边就行(因为把一个奇环和一个偶环的公共边删去还是一个奇环)

    当有多条奇环时,删掉被所有奇环覆盖的且不被偶环覆盖的边。

    代码细节很多具体看代码

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 using namespace std;
     5 const int maxn=500000;
     6 int n,m,sum,ans,cnt;
     7 int f[maxn],to[maxn<<1],next[maxn<<1],book[maxn<<1],head[maxn],pa[maxn],pb[maxn],vis[maxn],dep[maxn];
     8 int fa[maxn][31],Log[maxn],pc[maxn],s1[maxn],s0[maxn],from[maxn],bok[maxn];
     9 inline void add(int a,int b){
    10     to[++cnt]=b;
    11     next[cnt]=head[a];
    12     head[a]=cnt;
    13 }
    14 void dfs1(int x){
    15     vis[x]=1;
    16     for(int i=head[x];i;i=next[i])  
    17         if(!vis[to[i]])
    18             book[i]=1,fa[to[i]][0]=x,dep[to[i]]=dep[x]+1,from[to[i]]=(i>>1),dfs1(to[i]);
    19 }
    20 int lca(int u,int v){
    21     if(dep[u]<dep[v])swap(u,v);
    22     for(int i=30;i>=0;i--){
    23         if(dep[fa[u][i]]>=dep[v])u=fa[u][i];
    24     }
    25     if(u==v)return v;
    26     for(int i=30;i>=0;i--){
    27         if(fa[u][i]!=fa[v][i]){
    28             u=fa[u][i];v=fa[v][i];
    29         }
    30     }
    31     return fa[u][0];
    32 }
    33 void dfs2(int x){
    34     for(int i=head[x];i;i=next[i])  
    35         if(book[i])  
    36             dfs2(to[i]),s1[x]+=s1[to[i]],s0[x]+=s0[to[i]];
    37 }
    38 int main()
    39 {
    40     scanf("%d%d",&n,&m);
    41     cnt=1;
    42     int i,j;
    43     for(i=1;i<=m;i++){
    44         scanf("%d%d",&pa[i],&pb[i]);add(pa[i],pb[i]);add(pb[i],pa[i]);
    45     }
    46     for(i=1;i<=n;i++)    if(!vis[i]) dep[i]=1,dfs1(i);
    47     for(int i=1;i<=30;i++)
    48         for(int j=1;j<=n;j++){
    49             fa[j][i]=fa[fa[j][i-1]][i-1];
    50         }
    51     for(i=1;i<=m;i++)    
    52     if(!book[i*2]&&!book[i*2+1]){
    53         pc[i]=lca(pa[i],pb[i]);
    54         if(!((dep[pa[i]]^dep[pb[i]])&1))sum++,s1[pa[i]]++,s1[pb[i]]++,s1[pc[i]]-=2;
    55         else s0[pa[i]]++,s0[pb[i]]++,s0[pc[i]]-=2;
    56     }
    57     for(i=1;i<=n;i++)if(dep[i]==1)dfs2(i);
    58     if(!sum){
    59         printf("%d
    ",m);
    60         for(i=1;i<=m;i++)printf("%d ",i);
    61         return 0;
    62     }
    63     if(sum==1)
    64         for(i=1;i<=m;i++)
    65             if(!book[i*2]&&!book[i*2+1]&&!((dep[pa[i]]^dep[pb[i]])&1))bok[i]=1,ans++;
    66     for(i=1;i<=n;i++)
    67         if(s1[i]==sum&&!s0[i])bok[from[i]]=1,ans++;
    68     printf("%d
    ",ans);
    69     for(i=1;i<=m;i++)
    70         if(bok[i])printf("%d ",i);
    71     return 0;
    72 }
    View Code
  • 相关阅读:
    【2020-05-17】人生十三信条
    【2020-05-16】评价与骄傲
    【2020-05-15】每天都充满向上的激情
    【04NOIP普及组】火星人(信息学奥赛一本通 1929)(洛谷 1088)
    next_permutation(全排列算法)
    【03NOIP普及组】麦森数(信息学奥赛一本通 1925)(洛谷 1045)
    快速幂
    【03NOIP普及组】栈(信息学奥赛一本通 1924)(洛谷 1044)
    【06NOIP普及组】数列(信息学奥赛一本通 1937)(洛谷 1062)
    【00NOIP普及组】计算器的改良(信息学奥赛一本通 1910)(洛谷 1022)
  • 原文地址:https://www.cnblogs.com/Xu-daxia/p/9384349.html
Copyright © 2020-2023  润新知