zoukankan      html  css  js  c++  java
  • [并差集][lca][dfs] Jzoj P5798 树

    Description

    我们有一颗从1到n编号的n个结点的树,此外,您将从树中获得M个节点对,形式为(a1,b1),(a2,b2),…(am,bm).
    我们需要给每一条边定向,使得每一对节点对存在一条从ai到bi或从bi到ai的路径。
    现在要求方案数,对10^9+7取mod即可。
     

    Input

    第一行两个整数,n,m
    接下来n-1行,每一行两个整数,描述一条树边。
    接下来m行,描述ai,bi

    Output

    输出一个整数,表示方案数对10^9+7取mod
     

    Sample Input

    input1:
    4 1
    1 2
    2 3
    3 4
    2 4
    input2:
    7 2
    1 2
    1 3
    4 2
    2 5
    6 5
    5 7
    1 7
    2 6 
    input3:
    4 3
    1 2
    1 3
    1 4
    2 3
    2 4
    3 4 

    Sample Output

    output1:
    4
    output2:
    8
    output3:
    0
     

    Data Constraint

    对于前20%的数据,保证是一条链。
    另有40%的数据,n,m<=5000
    对于100%的数据,n,m<=300000

    题解

    • 发现,对于一对点(ai,bi)
    • 只要其中一条被确定了,其它都被确定了,而且黄色和红色的方向相反
    • 可以用并差集,两个点之间有关系的可以打入同一个并差集里
    • 这样最后的答案就是2^并差集的个数
    • 其中,并差集要按秩合并
    • 现在,考虑一下0的情况
    • 在维护并差集时还要维护一个信息,就是当前方向与父亲的方向是否相反,这个异或一下就好了
    • 那么对于两个点(a,b),如果要使它们可行,它们的路径要相反
    • 因为,按照并差集每次会将下面的某个点连到最上面的祖先,那么求会产生上图(ai,bi)的情况
    • 就要方向相反

    代码

      1 #include <cstdio>
      2 #include <iostream>
      3 #include <cstring>
      4 using namespace std;
      5 const long long mo=1e9+7;
      6 struct edge {int to,from; }e[300010*2];
      7 int fa[300010],p[300010][3],f[300010][20],deep[300010],w[300010],head[300010],cnt,n,m;
      8 bool boo;
      9 void insert(int x,int y) { e[++cnt].to=y; e[cnt].from=head[x]; head[x]=cnt; }
     10 void dfs(int x,int fa)
     11 {
     12     deep[x]=deep[fa]+1;
     13     for (int i=head[x];i;i=e[i].from)
     14     {
     15         int v=e[i].to;
     16         if (v==fa) continue;
     17         f[v][0]=x;
     18         dfs(v,x);
     19     }
     20 }
     21 int getlca(int x,int y)
     22 {
     23     if (deep[x]>deep[y]) swap(x,y);
     24     for (int i=18;i>=0;i--)
     25         if (deep[f[y][i]]>=deep[x])
     26             y=f[y][i];    
     27     if (x==y) return x;
     28     for (int i=18;i>=0;i--)
     29         if (f[x][i]!=f[y][i])
     30             x=f[x][i],y=f[y][i];
     31     return f[x][0];
     32 }
     33 int getfather(int x)
     34 {
     35     if (fa[x]==x) return x;
     36     int d=fa[x];
     37     fa[x]=getfather(fa[x]);
     38     w[x]=w[x]^w[d];
     39     return fa[x];
     40 }
     41 void together(int x,int lca)
     42 {
     43     x=getfather(x);
     44     while (deep[x]-2>=deep[lca])
     45     {
     46         int v=f[x][0];
     47         v=getfather(v);
     48         fa[x]=v;
     49         x=getfather(x);
     50     }
     51 }
     52 int main()
     53 {
     54     freopen("usmjeri.in","r",stdin);
     55     freopen("usmjeri.out","w",stdout);
     56     scanf("%d%d",&n,&m);
     57     for (int i=1;i<=n-1;i++)
     58     {
     59         int u,v;
     60         scanf("%d%d",&u,&v);
     61         insert(u,v),insert(v,u);
     62     }
     63     dfs(1,0); f[1][0]=1;
     64     for (int i=1;i<=18;i++)
     65         for (int j=1;j<=n;j++)
     66             f[j][i]=f[f[j][i-1]][i-1];
     67     for (int i=1;i<=n;i++) fa[i]=i;
     68     for (int i=1;i<=m;i++)    
     69     {
     70         int u,v;
     71         scanf("%d%d",&u,&v);
     72         int lca=getlca(u,v);
     73         together(u,lca),together(v,lca);
     74         p[i][0]=u,p[i][1]=v,p[i][2]=lca;
     75     }
     76     boo=1;
     77     for (int i=1;i<=m;i++)
     78     {
     79         int x=p[i][0],y=p[i][1],lca=p[i][2];
     80         if (x==lca||y==lca) continue;
     81         int u=getfather(x),v=getfather(y);
     82         if (u==v)
     83         {
     84             if ((w[x]^w[y])!=1) 
     85             {
     86                 printf("0"); 
     87                 return 0; 
     88             }
     89             continue;
     90         }
     91         fa[u]=v,w[u]=1^w[y]^w[x];
     92     }
     93     int ans=1;
     94     for (int i=2;i<=n;i++)
     95     {
     96         getfather(i);
     97         if (fa[i]==i) (ans*=2)%=mo;
     98     }
     99     printf("%d",ans);
    100     return 0;
    101 }
  • 相关阅读:
    Linux上查找
    Linux进程
    Linux重定向
    Linux上常用的基本命令
    LInux上返回到切换目录前的目录
    【网络知识之一】4/7层网络模型
    【操作系统之十五】iptables黑白名单、自定义链、网络防火墙、常用动作
    【操作系统之十四】iptables扩展模块
    【操作系统之十三】Netfilter与iptables
    【操作系统之十二】分支预测、CPU亲和性(affinity)
  • 原文地址:https://www.cnblogs.com/Comfortable/p/9464089.html
Copyright © 2011-2022 走看看