[关闭]
@ysner 2018-11-04T14:31:04.000000Z 字数 2127 阅读 1766

[ZJOI2012]灾难

图论 拓扑排序


题面

戳我

解析

一道挺不错的图论题。

算法

模拟。
暴力随便秒。
咕谷上居然有

  1. il void dfs(re int u)
  2. {
  3. for(re int i=h[u];i+1;i=e[i].nxt)
  4. {
  5. re int v=e[i].to;
  6. if(!--g[v]) ++ans,dfs(v);
  7. }
  8. }
  9. int main()
  10. {
  11. memset(h,-1,sizeof(h));
  12. n=gi();
  13. fp(i,1,n)
  14. {
  15. re int x=gi();
  16. while(x)
  17. {
  18. add(x,i);++d[i];
  19. x=gi();
  20. }
  21. }
  22. fp(i,1,n)
  23. {
  24. fp(j,1,n) g[j]=d[j];
  25. ans=0,dfs(i),printf("%d\n",ans);
  26. }
  27. return 0;
  28. }

算法

一个点灭绝,要求其所有入度灭绝。
它所有入度灭绝,要求它所有入度的灭绝。
这样,就说明这个点对的灾难值有贡献。

比较容易想到的,但这样复杂度还是
考虑到如果一个点单独对有贡献,那么所有对它有贡献的点也对有贡献。
这种关系实际为包含,可以用树形结构中的父子关系体现。

于是我们可以依此关系重建树。
想想这是一张有向无环图,八成考拓扑排序。
那么就按拓扑序建树,每个点的父亲就是它所有入度点的

必须用倍增求,因为这是动态维护信息。
存原图,存反图,存树。

  1. #include<iostream>
  2. #include<cmath>
  3. #include<cstdio>
  4. #include<cstdlib>
  5. #include<cstring>
  6. #include<algorithm>
  7. #include<queue>
  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=1e5+100;
  15. int n,d[N],ans[N],sta[N],top,f[17][N],deep[N];
  16. struct graph
  17. {
  18. int h[N],cnt;
  19. struct Edge{int to,nxt;}e[N<<1];
  20. il graph(){memset(h,-1,sizeof(h));}
  21. il void add(re int u,re int v){e[++cnt]=(Edge){v,h[u]};h[u]=cnt;}
  22. }t[3];
  23. queue<int>Q;
  24. il ll gi()
  25. {
  26. re ll x=0,t=1;
  27. re char ch=getchar();
  28. while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  29. if(ch=='-') t=-1,ch=getchar();
  30. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  31. return x*t;
  32. }
  33. il void Toposort()
  34. {
  35. fp(i,1,n) if(!d[i]) Q.push(i);
  36. while(!Q.empty())
  37. {
  38. re int u=Q.front();Q.pop();sta[++top]=u;
  39. for(re int i=t[0].h[u];i+1;i=t[0].e[i].nxt)
  40. {
  41. re int v=t[0].e[i].to;
  42. if(!--d[v]) Q.push(v);
  43. }
  44. }
  45. }
  46. il int getlca(re int u,re int v)
  47. {
  48. if(deep[u]<deep[v]) swap(u,v);
  49. fq(i,16,0) if(deep[f[i][u]]>=deep[v]) u=f[i][u];
  50. if(u==v) return u;
  51. fq(i,16,0) if(f[i][u]^f[i][v]) u=f[i][u],v=f[i][v];
  52. return f[0][u];
  53. }
  54. il void dfs(re int u)
  55. {
  56. for(re int i=t[2].h[u];i+1;i=t[2].e[i].nxt)
  57. {
  58. re int v=t[2].e[i].to;
  59. dfs(v);
  60. ans[u]+=ans[v];
  61. }
  62. ++ans[u];
  63. }
  64. int main()
  65. {
  66. n=gi();
  67. fp(i,1,n)
  68. {
  69. re int x=gi();
  70. while(x)
  71. {
  72. t[0].add(x,i);t[1].add(i,x);++d[i];x=gi();
  73. }
  74. }
  75. Toposort();
  76. fp(i,1,n)
  77. {
  78. re int u=sta[i],lca=-1;
  79. for(re int j=t[1].h[u];j+1;j=t[1].e[j].nxt)
  80. {
  81. re int v=t[1].e[j].to;
  82. if(lca==-1) lca=v;else lca=getlca(lca,v);
  83. }
  84. if(lca==-1) lca=0;
  85. t[2].add(lca,u);
  86. deep[u]=deep[lca]+1;
  87. f[0][u]=lca;
  88. fp(j,1,16) f[j][u]=f[j-1][f[j-1][u]];
  89. }
  90. dfs(0);
  91. fp(i,1,n) printf("%d\n",ans[i]-1);
  92. return 0;
  93. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注