[关闭]
@ysner 2018-10-12T22:22:40.000000Z 字数 1994 阅读 1875

[2017SEERC]Divide and Conquer

差分 树形DP


题面

一个有个点的图,上面有有两棵不同的生成树。问至少切断几条边,可以使原图不联通。并输出方案数。

解析

或许是道树上差分模板题?

首先,由于只有条边,故所有点的最小度数只能为(若度数为,需要条边)。
所以答案也只能是

那么,肯定在某一棵生成树上只割了一条边。
一开始想法是枚举这条边是哪个,再查一查切断这条边后,该边两个端点被几条线段连接。
然而复杂度不对,差分,树链剖分+线段树

实际上把一棵树上的所有边都用来覆盖另一棵树(即覆盖两端点的树上路径),再统计一下哪条边被覆盖次数最少,(这棵树上只切一条边)就是答案。(代码中是因为边是双向的,都加了两次)
这个可以用差分来完成。

如果答案是,则可能在另一棵树上只割一条边。反向覆盖+差分来统计方案数即可。
复杂度。(使用)

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #include<vector>
  8. #define ll long long
  9. #define re register
  10. #define il inline
  11. #define fp(i,a,b) for(re int i=a;i<=b;i++)
  12. #define fq(i,a,b) for(re int i=a;i>=b;i--)
  13. using namespace std;
  14. const int N=2e6+100;
  15. int n,m,h[2][N],cnt[2],f[N],s[N],lca[N],vis[N],mn=1e9,ans;
  16. struct Edge{int to,nxt;}e[2][N<<1];
  17. il void add(re int u,re int v){e[m][++cnt[m]]=(Edge){v,h[m][u]};h[m][u]=cnt[m];}
  18. il int find(re int x){return x==f[x]?x:f[x]=find(f[x]);}
  19. il ll gi()
  20. {
  21. re ll x=0,t=1;
  22. re char ch=getchar();
  23. while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  24. if(ch=='-') t=-1,ch=getchar();
  25. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  26. return x*t;
  27. }
  28. il void dfs(re int u)
  29. {
  30. vis[u]=1;
  31. for(re int i=h[m][u];i+1;i=e[m][i].nxt)
  32. {
  33. re int v=e[m][i].to;
  34. if(vis[v]) continue;
  35. dfs(v);
  36. f[v]=u;
  37. }
  38. for(re int i=h[m^1][u];i+1;i=e[m^1][i].nxt)
  39. {
  40. re int v=e[m^1][i].to;
  41. if(vis[v]==2) lca[i>>1]=find(v);
  42. }
  43. vis[u]=2;
  44. }
  45. il void calc(re int u,re int fa)
  46. {
  47. for(re int i=h[m][u];i+1;i=e[m][i].nxt)
  48. {
  49. re int v=e[m][i].to;
  50. if(v==fa) continue;
  51. calc(v,u);
  52. s[u]+=s[v];
  53. }
  54. if(!fa) return;
  55. if((s[u]>>1)+1<mn) mn=(s[u]>>1)+1,ans=1;
  56. else if((s[u]>>1)+1==mn) ++ans;
  57. }
  58. il void solve()
  59. {
  60. memset(s,0,sizeof(s));memset(vis,0,sizeof(vis));
  61. fp(i,1,n) f[i]=i;
  62. dfs(1);
  63. fp(u,1,n)
  64. for(re int i=h[m^1][u];i+1;i=e[m^1][i].nxt)
  65. {
  66. re int v=e[m^1][i].to;
  67. ++s[u];++s[v];s[lca[i>>1]]-=2;
  68. }
  69. calc(1,0);
  70. }
  71. int main()
  72. {
  73. freopen("xianjian.in","r",stdin);
  74. freopen("xianjian.out","w",stdout);
  75. memset(h,-1,sizeof(h));cnt[0]=cnt[1]=1;
  76. n=gi();
  77. fp(i,1,2*n-2)
  78. {
  79. if(i==n) m=1;
  80. re int u=gi(),v=gi();
  81. add(u,v);add(v,u);
  82. }
  83. m=0;solve();
  84. if(mn==3) m=1,solve();
  85. printf("%d %d\n",mn,ans);
  86. fclose(stdin);
  87. fclose(stdout);
  88. return 0;
  89. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注