[并差集][lca][dfs] Jzoj P5798 树
Posted comfortable
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[并差集][lca][dfs] Jzoj P5798 树相关的知识,希望对你有一定的参考价值。
题解
- 发现,对于一对点(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 }
以上是关于[并差集][lca][dfs] Jzoj P5798 树的主要内容,如果未能解决你的问题,请参考以下文章
[差分][倍增lca][tarjan] Jzoj P3325 压力