[关闭]
@KirinBill 2018-01-25T09:40:15.000000Z 字数 38897 阅读 1355

点分治学习笔记

分治

目录


算法介绍

算法思想


算法流程

点分治和其它分治一样,都是递归进行的(虽然有非递归写法,但是反人类啊,没学会Orz),我们以处理点的子树为例:
1. 找到的子树的重心
2. 函数是计算子树中过的路径的贡献;
3. 遍历未访问过的儿子
4. 对于每个函数这里是计算子树中过但是到时有一段路径是重复的(即不是简单路径)这种路径数,也就是减去重复;
5. 递归,分治计算的子树;

伪代码:

  1. //求重心
  2. void get_grt(int u,int fa);
  3. //计算
  4. int solve(int u,int dis);
  5. int treeDC(int u){
  6. use[u]=true; //标记已经处理过了
  7. int ret=solve(u,0); //计算经过u的路径
  8. for(int i=he[u],v;i;i=ed[i].nex){
  9. v=ed[i].to;
  10. if(!use[v]){
  11. //减去重复,但距离初值要带上这条边,
  12. //这样才能表示路径中v到u这一段不是两条链,而是重叠了
  13. ret-=solve(v,ed[i].w);
  14. grt=0,sum_sz=sz[v]; //初始化重心,找到子树v的
  15. get_grt(v,0);
  16. ret+=treeDC(grt); //一定不能写成v,不然T上天!!!
  17. }
  18. }
  19. return ret;
  20. }

求重心的代码:

  1. void get_grt(int u,int fa){
  2. static int max_subT_sz[MAXN]={INT_MAX};
  3. sz[u]=1,max_subT_sz[u]=0;
  4. for(int i=he[u],v;i;i=ed[i].nex){
  5. v=ed[i].to;
  6. if(!use[v] && v!=fa){
  7. get_grt(v,u);
  8. sz[u]+=sz[v];
  9. max_subT_sz[u]=max(max_subT_sz[u],sz[v]);
  10. }
  11. }
  12. max_subT_sz[u]=max(max_subT_sz[u],sum_sz-sz[u]);
  13. if(max_subT_sz[u]<max_subT_sz[grt]) grt=u;
  14. }

练习

普通点分治

1.[BZOJ 1468] Tree

代码:

  1. #include <cstdio>
  2. #include <algorithm>
  3. #include <climits>
  4. using std::sort;
  5. using std::max;
  6. const int MAXN=40005;
  7. int k;
  8. int grt,sum_sz;
  9. int he[MAXN];
  10. int de[MAXN],sz[MAXN];
  11. bool use[MAXN];
  12. struct line{int to,nex,w;}ed[MAXN<<1];
  13. inline void addE(int u,int v,int w){
  14. static int cnt;
  15. ed[++cnt]=(line){v,he[u],w};
  16. he[u]=cnt;
  17. }
  18. //找到重心
  19. void get_grt(int u,int fa){
  20. static int max_subT[MAXN]={INT_MAX};
  21. sz[u]=1,max_subT[u]=0;
  22. for(int i=he[u],v;i;i=ed[i].nex){
  23. v=ed[i].to;
  24. if(!use[v] && v!=fa){
  25. get_grt(v,u);
  26. sz[u]+=sz[v];
  27. max_subT[u]=max(max_subT[u],sz[v]);
  28. }
  29. }
  30. //无根树,翻过来的也是子树
  31. max_subT[u]=max(max_subT[u],sum_sz-sz[u]);
  32. //更新重心
  33. if(max_subT[u]<max_subT[grt]) grt=u;
  34. }
  35. void DFS(int u,int fa,int de){
  36. ::de[++::de[0]]=de;
  37. for(int i=he[u],v;i;i=ed[i].nex){
  38. v=ed[i].to;
  39. if(!use[v] && v!=fa) DFS(v,u,de+ed[i].w);
  40. }
  41. }
  42. inline int solve(int u,int _de){
  43. de[0]=0;
  44. DFS(u,0,_de);
  45. sort(de+1,de+de[0]+1);
  46. int l=1,r=de[0];
  47. int ret=0;
  48. while(l<r){
  49. //l和l+1,l+2,...,r构成点对,不是区间长
  50. if(de[l]+de[r]<=k) ret+=r-l,++l;
  51. else --r;
  52. }
  53. return ret;
  54. }
  55. int treeDC(int u){
  56. use[u]=true;
  57. int ret=solve(u,0);
  58. for(int i=he[u],v;i;i=ed[i].nex){
  59. v=ed[i].to;
  60. if(!use[v]){
  61. //减去重复情况
  62. ret-=solve(v,ed[i].w);
  63. grt=0,sum_sz=sz[v];
  64. get_grt(v,0);
  65. ret+=treeDC(grt);
  66. }
  67. }
  68. return ret;
  69. }
  70. int main(){
  71. int n;
  72. scanf("%d",&n);
  73. for(int i=1,u,v,w;i<n;++i){
  74. scanf("%d%d%d",&u,&v,&w);
  75. addE(u,v,w),addE(v,u,w);
  76. }
  77. scanf("%d",&k);
  78. sum_sz=n;
  79. get_grt(1,0);
  80. printf("%d",treeDC(grt));
  81. return 0;
  82. }

2.[BZOJ 1316] 树上的询问

代码:

  1. #include <cstdio>
  2. #include <algorithm>
  3. #include <climits>
  4. using std::max;
  5. using std::sort;
  6. const int MAXN=10005,MAXQ=105;
  7. int q,grt,sum_sz;
  8. int he[MAXN],de[MAXN],sz[MAXN];
  9. int qry[MAXN],ans[MAXQ];
  10. bool use[MAXN];
  11. struct line{int to,nex,w;}ed[MAXN<<1];
  12. inline void addE(int u,int v,int w){
  13. static int cnt;
  14. ed[++cnt]=(line){v,he[u],w};
  15. he[u]=cnt;
  16. }
  17. void get_grt(int u,int fa){
  18. static int max_subT_sz[MAXN]={INT_MAX};
  19. sz[u]=1,max_subT_sz[u]=0;
  20. for(int i=he[u],v;i;i=ed[i].nex){
  21. v=ed[i].to;
  22. if(!use[v] && v!=fa){
  23. get_grt(v,u);
  24. sz[u]+=sz[v];
  25. max_subT_sz[u]=max(max_subT_sz[u],sz[v]);
  26. }
  27. }
  28. max_subT_sz[u]=max(max_subT_sz[u],sum_sz-sz[u]);
  29. if(max_subT_sz[u]<max_subT_sz[grt]) grt=u;
  30. }
  31. void DFS(int u,int fa,int de){
  32. ::de[++::de[0]]=de;
  33. for(int i=he[u],v;i;i=ed[i].nex){
  34. v=ed[i].to;
  35. if(!use[v] && v!=fa) DFS(v,u,de+ed[i].w);
  36. }
  37. }
  38. bool lt(int a,int b){return a<b;}
  39. bool leq(int a,int b){return a<=b;}
  40. inline int solve(int k,bool jud(int,int)){
  41. int l=1,r=de[0],ret=0;
  42. if(k==0) return jud(de[1],k);
  43. while(l<r){
  44. if(jud(de[l]+de[r],k)) ret+=r-l,++l;
  45. else --r;
  46. }
  47. return ret;
  48. }
  49. void treeDC(int u){
  50. use[u]=true;
  51. de[0]=0;
  52. DFS(u,0,0);
  53. sort(de+1,de+de[0]+1);
  54. for(int i=1;i<=q;++i)
  55. ans[i]+=solve(qry[i],leq)-solve(qry[i],lt);
  56. for(int i=he[u],v,w;i;i=ed[i].nex){
  57. v=ed[i].to;
  58. if(use[v]) continue;
  59. w=ed[i].w;
  60. de[0]=0;
  61. DFS(v,0,ed[i].w);
  62. sort(de+1,de+de[0]+1);
  63. for(int j=1;j<=q;++j)
  64. ans[j]-=solve(qry[j],leq)-solve(qry[j],lt);
  65. grt=0,sum_sz=sz[v];
  66. get_grt(v,0);
  67. treeDC(grt);
  68. }
  69. }
  70. int main(){
  71. int n;
  72. scanf("%d%d",&n,&q);
  73. for(int i=1,u,v,w;i<n;++i){
  74. scanf("%d%d%d",&u,&v,&w);
  75. addE(u,v,w),addE(v,u,w);
  76. }
  77. for(int i=1;i<=q;++i)
  78. scanf("%d",&qry[i]);
  79. sum_sz=n;
  80. get_grt(1,0);
  81. treeDC(grt);
  82. for(int i=1;i<=q;++i){
  83. if(ans[i]) puts("Yes");
  84. else puts("No");
  85. }
  86. return 0;
  87. }

3.[BZOJ 2152] 聪聪可可

代码:

  1. #include <cstdio>
  2. #include <algorithm>
  3. #include <climits>
  4. #include <cstring>
  5. using std::max;
  6. const int MAXN=20005;
  7. int grt,sum_sz;
  8. int he[MAXN];
  9. int sz[MAXN],de[MAXN],de_mod3[3];
  10. bool use[MAXN];
  11. struct line{int to,nex,w;}ed[MAXN<<1];
  12. inline int gcd(int a,int b){
  13. int r;
  14. while(b){
  15. r=a%b;
  16. a=b,b=r;
  17. }
  18. return a;
  19. }
  20. inline void addE(int u,int v,int w){
  21. static int cnt;
  22. ed[++cnt]=(line){v,he[u],w};
  23. he[u]=cnt;
  24. }
  25. void get_grt(int u,int fa){
  26. static int max_subT[MAXN]={INT_MAX};
  27. sz[u]=1,max_subT[u]=0;
  28. for(int i=he[u],v;i;i=ed[i].nex){
  29. v=ed[i].to;
  30. if(!use[v] && v!=fa){
  31. get_grt(v,u);
  32. sz[u]+=sz[v];
  33. max_subT[u]=max(max_subT[u],sz[v]);
  34. }
  35. }
  36. max_subT[u]=max(max_subT[u],sum_sz-sz[u]);
  37. if(max_subT[u]<max_subT[grt]) grt=u;
  38. }
  39. void DFS(int u,int fa,int de){
  40. ++de_mod3[de%3];
  41. for(int i=he[u],v;i;i=ed[i].nex){
  42. v=ed[i].to;
  43. if(!use[v] && v!=fa)
  44. DFS(v,u,de+ed[i].w);
  45. }
  46. }
  47. inline int solve(int u,int _de){
  48. memset(de_mod3,0,sizeof(de_mod3));
  49. DFS(u,0,_de);
  50. //两个人选,所以两个端点是两个方案
  51. return de_mod3[0]*de_mod3[0]+(de_mod3[1]*de_mod3[2]<<1);
  52. }
  53. int treeDC(int u){
  54. use[u]=true;
  55. int ret=solve(u,0);
  56. for(int i=he[u],v;i;i=ed[i].nex){
  57. v=ed[i].to;
  58. if(!use[v]){
  59. ret-=solve(v,ed[i].w);
  60. grt=0,sum_sz=sz[v];
  61. get_grt(v,0);
  62. ret+=treeDC(grt);
  63. }
  64. }
  65. return ret;
  66. }
  67. int main(){
  68. int n;
  69. scanf("%d",&n);
  70. for(int i=1,u,v,w;i<n;++i){
  71. scanf("%d%d%d",&u,&v,&w);
  72. addE(u,v,w),addE(v,u,w);
  73. }
  74. sum_sz=n;
  75. get_grt(1,0);
  76. int cnt=treeDC(grt),tot=n*n;
  77. int gcd=::gcd(cnt,tot);
  78. printf("%d/%d",cnt/gcd,tot/gcd);
  79. return 0;
  80. }

4.[Codeforces 715C] Digit Tree

题目大意:给你一棵个点的树,每条边上有一个数字(~),给出一个与互质的数,问整棵树上有多少条路径满足从起点走到终点的边上形成的十进制数是的倍数。.

代码:

  1. #include <cstdio>
  2. #include <algorithm>
  3. #include <climits>
  4. using std::max;
  5. using std::sort;
  6. using std::lower_bound;
  7. using std::upper_bound;
  8. const int MAXN=100005;
  9. int grt,m,sum_sz,tot;
  10. int he[MAXN],sz[MAXN];
  11. int de[MAXN],up[MAXN],dwn[MAXN];
  12. int pow10[MAXN];
  13. bool use[MAXN];
  14. struct line{int to,nex,w;}ed[MAXN<<1];
  15. inline void addE(int u,int v,int w){
  16. static int cnt;
  17. ed[++cnt]=(line){v,he[u],w};
  18. he[u]=cnt;
  19. }
  20. int exgcd(int a,int &x,int b,int &y){
  21. if(!b){
  22. x=1,y=0;
  23. return a;
  24. }
  25. int ret=exgcd(b,y,a%b,x);
  26. y-=a/b*x;
  27. return ret;
  28. }
  29. void get_grt(int u,int fa){
  30. static int max_subT_sz[MAXN]={INT_MAX};
  31. sz[u]=1,max_subT_sz[u]=0;
  32. for(int i=he[u],v;i;i=ed[i].nex){
  33. v=ed[i].to;
  34. if(!use[v] && v!=fa){
  35. get_grt(v,u);
  36. sz[u]+=sz[v];
  37. max_subT_sz[u]=max(max_subT_sz[u],sz[v]);
  38. }
  39. }
  40. max_subT_sz[u]=max(max_subT_sz[u],sum_sz-sz[u]);
  41. if(max_subT_sz[u]<max_subT_sz[grt]) grt=u;
  42. }
  43. void DFS(int u,int fa,int de,int up,int dwn){
  44. ++tot;
  45. ::de[tot]=de,::up[tot]=up,::dwn[tot]=dwn;
  46. for(int i=he[u],v;i;i=ed[i].nex){
  47. v=ed[i].to;
  48. if(!use[v] && v!=fa)
  49. DFS(v,u,de+1,(up+(long long)ed[i].w*pow10[de]%m)%m,((long long)dwn*10%m+ed[i].w)%m);
  50. }
  51. }
  52. //ax=b mod c
  53. inline int equiv(int a,int b,int c){
  54. int x,y;
  55. exgcd(a,x,c,y);
  56. return (long long)b*((x%c+c)%c)%c;
  57. }
  58. inline int cal_sum(int val){
  59. return upper_bound(up+1,up+tot+1,val)-lower_bound(up+1,up+tot+1,val);
  60. }
  61. inline long long solve(int u,int _dis){
  62. tot=0;
  63. DFS(u,0,(bool)_dis,_dis%m,_dis%m);
  64. sort(up+1,up+tot+1);
  65. long long ret=0;
  66. for(int i=1,up;i<=tot;++i){
  67. up=equiv(pow10[de[i]],(-dwn[i]+m)%m,m);
  68. ret+=cal_sum(up);
  69. }
  70. //此时,会多计算一个a=b=0的情况,也就是自己一个点
  71. if(_dis==0) --ret;
  72. return ret;
  73. }
  74. long long treeDC(int u){
  75. use[u]=true;
  76. long long ret=solve(u,0);
  77. for(int i=he[u],v;i;i=ed[i].nex){
  78. v=ed[i].to;
  79. if(!use[v]){
  80. ret-=solve(v,ed[i].w);
  81. grt=0,sum_sz=sz[v];
  82. get_grt(v,0);
  83. ret+=treeDC(grt);
  84. }
  85. }
  86. return ret;
  87. }
  88. int main(){
  89. int n;
  90. scanf("%d%d",&n,&m);
  91. for(int i=1,u,v,w;i<n;++i){
  92. scanf("%d%d%d",&u,&v,&w);
  93. ++u,++v;
  94. addE(u,v,w),addE(v,u,w);
  95. }
  96. pow10[0]=1;
  97. for(int i=1;i<=n;++i)
  98. pow10[i]=(long long)pow10[i-1]*10%m;
  99. sum_sz=n;
  100. get_grt(1,0);
  101. printf("%I64d",treeDC(grt));
  102. return 0;
  103. }

5.[BZOJ 3697] 采药人的路径

代码:

  1. #include <cstdio>
  2. #include <algorithm>
  3. #include <climits>
  4. #include <cmath>
  5. using std::max;
  6. using std::abs;
  7. const int MAXN=100005;
  8. int grt,sum_sz,max_dis;
  9. int he[MAXN],sz[MAXN];
  10. int tmp[2][MAXN<<1];
  11. int *have[2]={tmp[0]+MAXN,tmp[1]+MAXN};
  12. bool use[MAXN];
  13. struct line{int to,nex,w;}ed[MAXN<<1];
  14. inline void addE(int u,int v,int w){
  15. static int cnt;
  16. ed[++cnt]=(line){v,he[u],w};
  17. he[u]=cnt;
  18. }
  19. void get_grt(int u,int fa){
  20. static int max_subT_sz[MAXN]={INT_MAX};
  21. sz[u]=1,max_subT_sz[u]=0;
  22. for(int i=he[u],v;i;i=ed[i].nex){
  23. v=ed[i].to;
  24. if(!use[v] && v!=fa){
  25. get_grt(v,u);
  26. sz[u]+=sz[v];
  27. max_subT_sz[u]=max(max_subT_sz[u],sz[v]);
  28. }
  29. }
  30. max_subT_sz[u]=max(max_subT_sz[u],sum_sz-sz[u]);
  31. if(max_subT_sz[u]<max_subT_sz[grt]) grt=u;
  32. }
  33. void DFS(int u,int fa,int dis){
  34. static int tmp[MAXN<<1];
  35. static int *pre=tmp+MAXN;
  36. max_dis=max(max_dis,abs(dis));
  37. ++have[(bool)pre[dis]][dis];
  38. ++pre[dis];
  39. for(int i=he[u],v;i;i=ed[i].nex){
  40. v=ed[i].to;
  41. if(!use[v] && v!=fa) DFS(v,u,dis+ed[i].w);
  42. }
  43. --pre[dis];
  44. }
  45. inline long long solve(int u){
  46. static int tmp[2][MAXN<<1];
  47. static int *sum_have[2]={tmp[0]+MAXN,tmp[1]+MAXN};
  48. sum_have[0][0]=1;
  49. max_dis=0;
  50. long long ret=0;
  51. for(int i=he[u],v;i;i=ed[i].nex){
  52. v=ed[i].to;
  53. if(use[v]) continue;
  54. DFS(v,0,ed[i].w);
  55. //休息站在重心上的
  56. ret+=(long long)have[0][0]*(sum_have[0][0]-1);
  57. for(int i=-max_dis;i<=max_dis;++i){
  58. ret+=(long long)sum_have[1][i]*have[1][-i];
  59. ret+=(long long)sum_have[0][i]*have[1][-i];
  60. ret+=(long long)sum_have[1][i]*have[0][-i];
  61. }
  62. for(int i=-max_dis;i<=max_dis;++i){
  63. sum_have[0][i]+=have[0][i];
  64. sum_have[1][i]+=have[1][i];
  65. have[0][i]=have[1][i]=0;
  66. }
  67. }
  68. for(int i=-max_dis;i<=max_dis;++i)
  69. sum_have[0][i]=sum_have[1][i]=0;
  70. return ret;
  71. }
  72. long long treeDC(int u){
  73. use[u]=true;
  74. long long ret=solve(u);
  75. for(int i=he[u],v;i;i=ed[i].nex){
  76. v=ed[i].to;
  77. if(!use[v]){
  78. grt=0,sum_sz=sz[v];
  79. get_grt(v,0);
  80. ret+=treeDC(grt);
  81. }
  82. }
  83. return ret;
  84. }
  85. int main(){
  86. int n;
  87. scanf("%d",&n);
  88. for(int i=1,u,v,w;i<n;++i){
  89. scanf("%d%d%d",&u,&v,&w);
  90. if(w==0) w=-1;
  91. addE(u,v,w),addE(v,u,w);
  92. }
  93. sum_sz=n;
  94. get_grt(1,0);
  95. printf("%lld",treeDC(grt));
  96. return 0;
  97. }

6.[FJOI 2014] 最短路径树问题

代码:

  1. #include <cstdio>
  2. #include <algorithm>
  3. #include <climits>
  4. #include <queue>
  5. #include <vector>
  6. #include <functional>
  7. #include <cstring>
  8. using std::min;
  9. using std::max;
  10. using std::priority_queue;
  11. using std::vector;
  12. using std::greater;
  13. const int MAXN=30005,MAXM=60005;
  14. int n,k,ecnt;
  15. int grt,sum_sz;
  16. int ans,tot;
  17. int he[MAXN],sz[MAXN],dis[MAXN],pre[MAXN];
  18. int maxl[MAXN],cnt[MAXN]={1}; //深度为0的只有当前根这一个,且dis=0
  19. bool use[MAXN];
  20. struct line{int to,nex,w;}ed[MAXM<<1];
  21. struct node{
  22. int id,dis;
  23. node(int _id=0,int _dis=0):id(_id),dis(_dis){}
  24. bool operator >(const node &that)const{
  25. return dis>that.dis || (dis==that.dis && id>that.id);
  26. }
  27. };
  28. inline void addE(int u,int v,int w){
  29. static int &cnt=ecnt;
  30. ed[++cnt]=(line){v,he[u],w};
  31. he[u]=cnt;
  32. }
  33. inline void Dijkstra(){
  34. static bool use[MAXN];
  35. static priority_queue<node,vector<node>,greater<node> > hp;
  36. memset(dis,0x7f,sizeof(dis));
  37. dis[1]=0;
  38. hp.push(node(1,0));
  39. int u;
  40. while(hp.size()){
  41. u=hp.top().id;
  42. hp.pop();
  43. if(use[u]) continue;
  44. use[u]=true;
  45. for(int i=he[u],v,d;i;i=ed[i].nex){
  46. v=ed[i].to,d=dis[u]+ed[i].w;
  47. if(dis[v]>d){
  48. dis[v]=d,pre[v]=u;
  49. hp.push(node(v,d));
  50. }
  51. }
  52. }
  53. }
  54. inline void rebuild(){
  55. ecnt=0;
  56. memset(he,0,sizeof(he));
  57. for(int i=2,w;i<=n;++i){
  58. w=dis[i]-dis[pre[i]];
  59. addE(pre[i],i,w),addE(i,pre[i],w);
  60. }
  61. }
  62. void get_grt(int u,int fa){
  63. static int max_subT_sz[MAXN]={INT_MAX};
  64. sz[u]=1,max_subT_sz[u]=0;
  65. for(int i=he[u],v;i;i=ed[i].nex){
  66. v=ed[i].to;
  67. if(!use[v] && v!=fa){
  68. get_grt(v,u);
  69. sz[u]+=sz[v];
  70. max_subT_sz[u]=max(max_subT_sz[u],sz[v]);
  71. }
  72. }
  73. max_subT_sz[u]=max(max_subT_sz[u],sum_sz-sz[u]);
  74. if(max_subT_sz[u]<max_subT_sz[grt]) grt=u;
  75. }
  76. void DFS_cal(int u,int fa,int de,int dis){
  77. //点数=边数+1...
  78. if(de>=k) return;
  79. if(cnt[k-(de+1)]){
  80. int d=dis+maxl[k-(de+1)];
  81. if(d>ans) ans=d,tot=cnt[k-(de+1)];
  82. else if(d==ans) tot+=cnt[k-(de+1)];
  83. }
  84. for(int i=he[u],v;i;i=ed[i].nex){
  85. v=ed[i].to;
  86. if(!use[v] && v!=fa)
  87. DFS_cal(v,u,de+1,dis+ed[i].w);
  88. }
  89. }
  90. void DFS_upd(int u,int fa,int de,int dis){
  91. if(de>=k) return; //剪枝
  92. if(dis>maxl[de]) maxl[de]=dis,cnt[de]=1;
  93. else if(dis==maxl[de]) ++cnt[de];
  94. for(int i=he[u],v;i;i=ed[i].nex){
  95. v=ed[i].to;
  96. if(!use[v] && v!=fa)
  97. DFS_upd(v,u,de+1,dis+ed[i].w);
  98. }
  99. }
  100. void treeDC(int u){
  101. use[u]=true;
  102. if(sum_sz<=k) return; //剪枝
  103. memset(maxl+1,0,sum_sz<<2);
  104. memset(cnt+1,0,sum_sz<<2);
  105. for(int i=he[u],v;i;i=ed[i].nex){
  106. v=ed[i].to;
  107. if(!use[v]){
  108. DFS_cal(v,0,1,ed[i].w);
  109. DFS_upd(v,0,1,ed[i].w);
  110. }
  111. }
  112. for(int i=he[u],v;i;i=ed[i].nex){
  113. v=ed[i].to;
  114. if(!use[v]){
  115. grt=0,sum_sz=sz[v];
  116. get_grt(v,0);
  117. treeDC(grt);
  118. }
  119. }
  120. }
  121. int main(){
  122. int m;
  123. scanf("%d%d%d",&n,&m,&k);
  124. for(int i=1,u,v,w;i<=m;++i){
  125. scanf("%d%d%d",&u,&v,&w);
  126. addE(u,v,w),addE(v,u,w);
  127. }
  128. Dijkstra();
  129. rebuild();
  130. sum_sz=n;
  131. get_grt(1,0);
  132. treeDC(grt);
  133. printf("%d %d",ans,tot);
  134. return 0;
  135. }

非递归版:[IOI 2011] Race

代码:

  1. #include <cstdio>
  2. #include <algorithm>
  3. #include <climits>
  4. #include <cstring>
  5. using std::min;
  6. using std::max;
  7. const int MAXN=200005,MAXK=1000005,INF=0x3f3f3f3f;
  8. int k,grt;
  9. int he[MAXN],fa[MAXN],de[MAXN],dis[MAXN];
  10. int minl[MAXK];
  11. int que[MAXN];
  12. int &bak=que[0];
  13. bool use[MAXN];
  14. struct line{int to,nex,w;}ed[MAXN<<1];
  15. inline void addE(int u,int v,int w){
  16. static int cnt;
  17. ed[++cnt]=(line){v,he[u],w};
  18. he[u]=cnt;
  19. }
  20. inline void get_grt(int rt){
  21. static int sz[MAXN],max_subT_sz[MAXN]={INT_MAX};
  22. bak=0;
  23. que[++bak]=rt;
  24. for(int frt=1,u;frt<=bak;++frt){
  25. u=que[frt];
  26. sz[u]=1,max_subT_sz[u]=0;
  27. for(int i=he[u],v;i;i=ed[i].nex){
  28. v=ed[i].to;
  29. if(use[v] || v==fa[u]) continue;
  30. fa[v]=u;
  31. que[++bak]=v;
  32. }
  33. }
  34. grt=0;
  35. for(int cur=bak,u,fa;cur;--cur){
  36. u=que[cur],fa=::fa[u];
  37. max_subT_sz[u]=max(max_subT_sz[u],bak-sz[u]);
  38. //玄之又玄...
  39. if(max_subT_sz[u]<=max_subT_sz[grt]) grt=u;
  40. sz[fa]+=sz[u];
  41. max_subT_sz[fa]=max(max_subT_sz[fa],sz[u]);
  42. //solve的BFS从grt开始,
  43. //与get_grt的顺序不同,
  44. //要清一下
  45. ::fa[u]=0;
  46. }
  47. }
  48. inline void BFS(){
  49. for(int frt=bak,u;frt<=bak;++frt){
  50. u=que[frt];
  51. for(int i=he[u],v;i;i=ed[i].nex){
  52. v=ed[i].to;
  53. if(use[v] || v==fa[u]) continue;
  54. fa[v]=u;
  55. dis[v]=dis[u]+ed[i].w,de[v]=de[u]+1;
  56. que[++bak]=v;
  57. }
  58. }
  59. }
  60. inline int solve(){
  61. bak=0;
  62. int ret=INT_MAX;
  63. for(int i=he[grt],u,lp;i;i=ed[i].nex){
  64. u=ed[i].to;
  65. if(use[u]) continue;
  66. dis[u]=ed[i].w,de[u]=1;
  67. que[++bak]=u,lp=bak;
  68. BFS();
  69. for(int cur=lp,v;cur<=bak;++cur){
  70. v=que[cur];
  71. if(dis[v]<=k) ret=min(ret,de[v]+minl[k-dis[v]]);
  72. }
  73. for(int cur=lp,v;cur<=bak;++cur){
  74. v=que[cur];
  75. if(dis[v]<=k) minl[dis[v]]=min(minl[dis[v]],de[v]);
  76. }
  77. }
  78. return ret;
  79. }
  80. int treeDC(int rt){
  81. use[rt]=true;
  82. int ret=solve();
  83. for(int cur=1,u;cur<=bak;++cur){
  84. u=que[cur];
  85. //原因同上
  86. fa[u]=0;
  87. //和虚树的类似,
  88. //每次只清用到的,
  89. //不要想复杂了。。。
  90. if(dis[u]<=k) minl[dis[u]]=INF;
  91. }
  92. for(int i=he[rt],v;i;i=ed[i].nex){
  93. v=ed[i].to;
  94. if(!use[v]){
  95. get_grt(v);
  96. ret=min(ret,treeDC(grt));
  97. }
  98. }
  99. return ret;
  100. }
  101. int main(){
  102. int n;
  103. scanf("%d%d",&n,&k);
  104. for(int i=1,u,v,w;i<n;++i){
  105. scanf("%d%d%d",&u,&v,&w);
  106. ++u,++v;
  107. addE(u,v,w),addE(v,u,w);
  108. }
  109. get_grt(1);
  110. memset(minl+1,0x3f,sizeof(minl)-4);
  111. int ans=treeDC(grt);
  112. if(ans>=INF) ans=-1;
  113. printf("%d",ans);
  114. return 0;
  115. }

点分治序列:[BZOJ 3784] 树上的路径

代码:

  1. #include <cstdio>
  2. #include <algorithm>
  3. #include <climits>
  4. #include <queue>
  5. #include <cmath>
  6. #include <cstring>
  7. using std::max;
  8. using std::priority_queue;
  9. const int MAXN=50005;
  10. int idx,grt,sum_sz;
  11. int he[MAXN],sz[MAXN];
  12. int len[MAXN<<4],lp[MAXN<<4],rp[MAXN<<4];
  13. bool use[MAXN];
  14. struct line{int to,nex,w;}ed[MAXN<<1];
  15. struct chain{
  16. int id,lp,rp,len;
  17. chain(int _id=0,int _lp=0,int _rp=0,int _len=0):id(_id),lp(_lp),rp(_rp),len(_len){}
  18. bool operator <(const chain &that)const{
  19. return len<that.len;
  20. }
  21. };
  22. priority_queue<chain> hp;
  23. class SparseTab{
  24. private:
  25. int c[20][MAXN<<4];
  26. public:
  27. void init(int a[],int n){
  28. for(int i=1;i<=n;++i) c[0][i]=i;
  29. for(int i=1,lim=log2(n);i<=lim;++i){
  30. for(int j=1;j+(1<<i)-1<=n;++j){
  31. if(len[c[i-1][j]]>len[c[i-1][j+(1<<i-1)]])
  32. c[i][j]=c[i-1][j];
  33. else c[i][j]=c[i-1][j+(1<<i-1)];
  34. }
  35. }
  36. }
  37. int qry(int l,int r){
  38. if(l>r) return 0;
  39. int k=log2(r-l+1);
  40. if(len[c[k][l]]>len[c[k][r-(1<<k)+1]])
  41. return c[k][l];
  42. else return c[k][r-(1<<k)+1];
  43. }
  44. }st;
  45. inline void addE(int u,int v,int w){
  46. static int cnt;
  47. ed[++cnt]=(line){v,he[u],w};
  48. he[u]=cnt;
  49. }
  50. void get_grt(int u,int fa){
  51. static int max_subT_sz[MAXN]={INT_MAX};
  52. sz[u]=1,max_subT_sz[u]=0;
  53. for(int i=he[u],v;i;i=ed[i].nex){
  54. v=ed[i].to;
  55. if(!use[v] && v!=fa){
  56. get_grt(v,u);
  57. sz[u]+=sz[v];
  58. max_subT_sz[u]=max(max_subT_sz[u],sz[v]);
  59. }
  60. }
  61. max_subT_sz[u]=max(max_subT_sz[u],sum_sz-sz[u]);
  62. if(max_subT_sz[u]<max_subT_sz[grt]) grt=u;
  63. }
  64. void DFS(int u,int fa,int dis,int rp){
  65. len[++idx]=dis;
  66. lp[idx]=lp[idx-1],::rp[idx]=rp;
  67. for(int i=he[u],v;i;i=ed[i].nex){
  68. v=ed[i].to;
  69. if(!use[v] && v!=fa) DFS(v,u,dis+ed[i].w,rp);
  70. }
  71. }
  72. void treeDC(int u){
  73. use[u]=true;
  74. len[++idx]=0;
  75. lp[idx]=rp[idx]=idx;
  76. for(int i=he[u],v;i;i=ed[i].nex){
  77. v=ed[i].to;
  78. if(!use[v]) DFS(v,u,ed[i].w,idx);
  79. }
  80. for(int i=he[u],v;i;i=ed[i].nex){
  81. v=ed[i].to;
  82. if(!use[v]){
  83. grt=0,sum_sz=sz[v];
  84. get_grt(v,0);
  85. treeDC(grt);
  86. }
  87. }
  88. }
  89. int main(){
  90. int n,m;
  91. scanf("%d%d",&n,&m);
  92. for(int i=1,u,v,w;i<n;++i){
  93. scanf("%d%d%d",&u,&v,&w);
  94. addE(u,v,w),addE(v,u,w);
  95. }
  96. sum_sz=n;
  97. get_grt(1,0);
  98. treeDC(grt);
  99. st.init(len,idx);
  100. for(int i=1;i<=idx;++i){
  101. if(lp[i]>rp[i]) continue;
  102. hp.push(chain(i,lp[i],rp[i],len[i]+len[st.qry(lp[i],rp[i])]));
  103. }
  104. chain now;
  105. for(int i=1,id,lp,rp,lmid,rmid,mid;i<=m;++i){
  106. now=hp.top();
  107. hp.pop();
  108. printf("%d\n",now.len);
  109. id=now.id,lp=now.lp,rp=now.rp;
  110. mid=st.qry(lp,rp);
  111. lmid=st.qry(lp,mid-1);
  112. if(lmid) hp.push(chain(id,lp,mid-1,len[id]+len[lmid]));
  113. rmid=st.qry(mid+1,rp);
  114. if(rmid) hp.push(chain(id,mid+1,rp,len[id]+len[rmid]));
  115. }
  116. return 0;
  117. }

基环树分治:[BZOJ 3648] 寝室管理

代码:

  1. #include <cstdio>
  2. #include <algorithm>
  3. #include <climits>
  4. #include <cstring>
  5. using std::max;
  6. using std::sort;
  7. const int MAXN=100005;
  8. int n,grt,k,sum_sz,cut1,cut2;
  9. int he[MAXN],sz[MAXN],de[MAXN],cir[MAXN];
  10. bool use[MAXN];
  11. struct line{int to,nex;}ed[MAXN<<1];
  12. class rev_BIT{
  13. private:
  14. long long c[MAXN];
  15. int lowbit(int x){return x&-x;}
  16. public:
  17. void add(int r){
  18. for(;r;r-=lowbit(r)) ++c[r];
  19. }
  20. long long qry(int l){
  21. //如果需要的剩下的长度非正了,
  22. //说明这条链已经满足条件了,
  23. //那么另一条链长度随意
  24. if(l<=0) l=1;
  25. long long ret=0;
  26. for(;l<=n;l+=lowbit(l))
  27. ret+=c[l];
  28. return ret;
  29. }
  30. }ta;
  31. inline void addE(int u,int v){
  32. static int cnt=1;
  33. ed[++cnt]=(line){v,he[u]};
  34. he[u]=cnt;
  35. }
  36. inline int revE(int i){return i^1;}
  37. bool find_cir(int u){
  38. static int pre[MAXN];
  39. static bool vis[MAXN];
  40. vis[u]=true;
  41. int fa=pre[u];
  42. for(int i=he[u],v;i;i=ed[i].nex){
  43. v=ed[i].to;
  44. if(v==fa) continue;
  45. if(vis[v]){
  46. cut1=i,cut2=revE(i);
  47. for(int now=u;now!=pre[v];now=pre[now])
  48. cir[++cir[0]]=now;
  49. return true;
  50. }
  51. pre[v]=u;
  52. if(find_cir(v)) return true;
  53. }
  54. return false;
  55. }
  56. void get_grt(int u,int fa){
  57. static int max_subT_sz[MAXN]={INT_MAX};
  58. sz[u]=1,max_subT_sz[u]=0;
  59. for(int i=he[u],v;i;i=ed[i].nex){
  60. if(i==cut1 || i==cut2) continue;
  61. v=ed[i].to;
  62. if(!use[v] && v!=fa){
  63. get_grt(v,u);
  64. sz[u]+=sz[v];
  65. max_subT_sz[u]=max(max_subT_sz[u],sz[v]);
  66. }
  67. }
  68. max_subT_sz[u]=max(max_subT_sz[u],sum_sz-sz[u]);
  69. if(max_subT_sz[u]<max_subT_sz[grt]) grt=u;
  70. }
  71. void DFS(int u,int fa,int de){
  72. ::de[++::de[0]]=de;
  73. for(int i=he[u],v;i;i=ed[i].nex){
  74. if(i==cut1 || i==cut2) continue;
  75. v=ed[i].to;
  76. if(!use[v] && v!=fa) DFS(v,u,de+1);
  77. }
  78. }
  79. inline long long solve(int u,int _de){
  80. de[0]=0;
  81. DFS(u,0,_de);
  82. sort(de+1,de+de[0]+1);
  83. int l=1,r=de[0];
  84. long long ret=0;
  85. while(l<r){
  86. if(de[l]+de[r]+1<k) ret+=r-l,++l;
  87. else --r;
  88. }
  89. return ret;
  90. }
  91. long long treeDC(int u){
  92. use[u]=true;
  93. long long ret=solve(u,0);
  94. for(int i=he[u],v;i;i=ed[i].nex){
  95. if(i==cut1 || i==cut2) continue;
  96. v=ed[i].to;
  97. if(!use[v]){
  98. ret-=solve(v,1);
  99. grt=0,sum_sz=sz[v];
  100. get_grt(v,0);
  101. ret+=treeDC(grt);
  102. }
  103. }
  104. return ret;
  105. }
  106. inline long long cal_cutE(){
  107. memset(use,false,sizeof(use));
  108. for(int i=1;i<=cir[0];++i)
  109. use[cir[i]]=true;
  110. long long ret=0;
  111. for(int i=1,u;i<=cir[0];++i){
  112. u=cir[i];
  113. de[0]=0;
  114. DFS(u,0,0);
  115. for(int j=1;j<=de[0];++j) //绕一圈到cir[cir[0]]
  116. ret+=ta.qry(k-(de[j]+(cir[0]-i+1)));
  117. //两段中间是cir[1]和cir[cir[0]],通过cut边相接
  118. for(int j=1;j<=de[0];++j) //直接到cir[1]
  119. ta.add(i+de[j]);
  120. }
  121. return ret;
  122. }
  123. int main(){
  124. int m;
  125. scanf("%d%d%d",&n,&m,&k);
  126. for(int i=1,u,v;i<=m;++i){
  127. scanf("%d%d",&u,&v);
  128. addE(u,v),addE(v,u);
  129. }
  130. find_cir(1);
  131. sum_sz=n;
  132. get_grt(1,0);
  133. long long ans=((long long)n*(n-1)>>1)-treeDC(grt);
  134. if(m==n) ans+=cal_cutE();
  135. printf("%lld",ans);
  136. return 0;
  137. }

重心树维护动态点分治

1.[BZOJ 3730] 震波

代码:

  1. #include <cstdio>
  2. #include <algorithm>
  3. #include <climits>
  4. #include <cmath>
  5. #include <cstring>
  6. using std::max;
  7. using std::swap;
  8. const int MAXN=100005;
  9. int n,sum_sz,grt;
  10. int he[MAXN],val[MAXN],fa[MAXN];
  11. int dfn[MAXN<<1],pos[MAXN],de[MAXN];
  12. int sz[MAXN];
  13. bool use[MAXN];
  14. struct line{int to,nex;}ed[MAXN<<1];
  15. class SparseTab{
  16. private:
  17. int c[18][MAXN<<1];
  18. public:
  19. void init(int a[],int n){
  20. memcpy(c[0]+1,a+1,n<<2);
  21. for(int i=1,lim=log2(n);i<=lim;++i){
  22. for(int j=1;j+(1<<i)-1<=n;++j){
  23. if(de[c[i-1][j]]<de[c[i-1][j+(1<<i-1)]])
  24. c[i][j]=c[i-1][j];
  25. else c[i][j]=c[i-1][j+(1<<i-1)];
  26. }
  27. }
  28. }
  29. int LCA(int u,int v){
  30. u=pos[u],v=pos[v];
  31. if(u>v) swap(u,v);
  32. int k=log2(v-u+1);
  33. if(de[c[k][u]]<de[c[k][v-(1<<k)+1]])
  34. return c[k][u];
  35. else return c[k][v-(1<<k)+1];
  36. }
  37. }st;
  38. class segT{
  39. private:
  40. struct node{
  41. int sum;
  42. node *ls,*rs;
  43. node(){sum=0,ls=rs=NULL;}
  44. }*rt;
  45. void ist(node *&u,int l,int r,int pos,int val){
  46. if(!u) u=new(node);
  47. u->sum+=val;
  48. if(l==r) return;
  49. int mid=l+r>>1;
  50. if(pos<=mid) ist(u->ls,l,mid,pos,val);
  51. else ist(u->rs,mid+1,r,pos,val);
  52. }
  53. int qry(node *u,int l,int r,int lp,int rp){
  54. if(!u) return 0;
  55. if(lp<=l && r<=rp) return u->sum;
  56. int mid=l+r>>1,ret=0;
  57. if(lp<=mid) ret=qry(u->ls,l,mid,lp,rp);
  58. if(rp>mid) ret+=qry(u->rs,mid+1,r,lp,rp);
  59. return ret;
  60. }
  61. public:
  62. void ist(int pos,int val){ist(rt,0,n,pos,val);}
  63. int qry(int lp,int rp){return qry(rt,0,n,lp,rp);}
  64. }plus[MAXN],minus[MAXN];
  65. inline void addE(int u,int v){
  66. static int cnt;
  67. ed[++cnt]=(line){v,he[u]};
  68. he[u]=cnt;
  69. }
  70. void DFS(int u,int fa){
  71. de[u]=de[fa]+1;
  72. dfn[++dfn[0]]=u;
  73. pos[u]=dfn[0];
  74. for(int i=he[u],v;i;i=ed[i].nex){
  75. v=ed[i].to;
  76. if(v!=fa){
  77. DFS(v,u);
  78. dfn[++dfn[0]]=u;
  79. }
  80. }
  81. }
  82. void get_grt(int u,int fa){
  83. static int max_subT_sz[MAXN]={INT_MAX};
  84. sz[u]=1,max_subT_sz[u]=0;
  85. for(int i=he[u],v;i;i=ed[i].nex){
  86. v=ed[i].to;
  87. if(!use[v] && v!=fa){
  88. get_grt(v,u);
  89. sz[u]+=sz[v];
  90. max_subT_sz[u]=max(max_subT_sz[u],sz[v]);
  91. }
  92. }
  93. max_subT_sz[u]=max(max_subT_sz[u],sum_sz-sz[u]);
  94. if(max_subT_sz[u]<max_subT_sz[grt]) grt=u;
  95. }
  96. void solve(int u,int fa,int de,segT &T){
  97. T.ist(de,val[u]);
  98. for(int i=he[u],v;i;i=ed[i].nex){
  99. v=ed[i].to;
  100. if(!use[v] && v!=fa)
  101. solve(v,u,de+1,T);
  102. }
  103. }
  104. void treeDC(int u){
  105. use[u]=true;
  106. solve(u,0,0,plus[u]);
  107. for(int i=he[u],v;i;i=ed[i].nex){
  108. v=ed[i].to;
  109. if(!use[v]){
  110. grt=0,sum_sz=sz[v];
  111. get_grt(v,0);
  112. fa[grt]=u;
  113. solve(v,0,1,minus[grt]);
  114. treeDC(grt);
  115. }
  116. }
  117. }
  118. inline int cal_dis(int u,int v){
  119. return de[u]+de[v]-(de[st.LCA(u,v)]<<1);
  120. }
  121. inline int qry(int u,int k){
  122. int ret=plus[u].qry(0,k);
  123. for(int now=u,dis;fa[now];now=fa[now]){
  124. dis=cal_dis(fa[now],u);
  125. if(k<dis) continue;
  126. ret+=plus[fa[now]].qry(0,k-dis);
  127. ret-=minus[now].qry(0,k-dis);
  128. }
  129. return ret;
  130. }
  131. inline void mdf(int u,int val){
  132. int dta=val-::val[u];
  133. ::val[u]=val;
  134. plus[u].ist(0,dta);
  135. for(int now=u,dis;fa[now];now=fa[now]){
  136. dis=cal_dis(fa[now],u);
  137. plus[fa[now]].ist(dis,dta);
  138. minus[now].ist(dis,dta);
  139. }
  140. }
  141. int main(){
  142. int m;
  143. scanf("%d%d",&n,&m);
  144. for(int i=1;i<=n;++i)
  145. scanf("%d",&val[i]);
  146. for(int i=1,u,v;i<n;++i){
  147. scanf("%d%d",&u,&v);
  148. addE(u,v),addE(v,u);
  149. }
  150. DFS(1,0);
  151. st.init(dfn,dfn[0]);
  152. sum_sz=n;
  153. get_grt(1,0);
  154. treeDC(grt);
  155. for(int i=1,opt,x,y,lastans=0;i<=m;++i){
  156. scanf("%d%d%d",&opt,&x,&y);
  157. x^=lastans,y^=lastans;
  158. if(opt==0){
  159. lastans=qry(x,y);
  160. printf("%d\n",lastans);
  161. }
  162. else mdf(x,y);
  163. }
  164. return 0;
  165. }

2.[BZOJ 4372] 烁烁的游戏

代码:

  1. #include <cstdio>
  2. #include <algorithm>
  3. #include <cstring>
  4. #include <climits>
  5. #include <cmath>
  6. using std::max;
  7. using std::swap;
  8. const int MAXN=1e5+5;
  9. int n,sum_sz,grt;
  10. int he[MAXN],sz[MAXN],fa[MAXN];
  11. int de[MAXN],dfn[MAXN<<1],pos[MAXN];
  12. bool use[MAXN];
  13. struct line{int to,nex;}ed[MAXN<<1];
  14. class SparseTab{
  15. private:
  16. int c[18][MAXN<<1];
  17. public:
  18. void init(int a[],int n){
  19. memcpy(c[0]+1,a+1,n<<2);
  20. for(int i=1,lim=log2(n);i<=lim;++i){
  21. for(int j=1;j+(1<<i)-1<=n;++j){
  22. if(de[c[i-1][j]]<de[c[i-1][j+(1<<i-1)]])
  23. c[i][j]=c[i-1][j];
  24. else c[i][j]=c[i-1][j+(1<<i-1)];
  25. }
  26. }
  27. }
  28. int LCA(int u,int v){
  29. u=pos[u],v=pos[v];
  30. if(u>v) swap(u,v);
  31. int k=log2(v-u+1);
  32. if(de[c[k][u]]<de[c[k][v-(1<<k)+1]])
  33. return c[k][u];
  34. else return c[k][v-(1<<k)+1];
  35. }
  36. }st;
  37. class segT{
  38. private:
  39. struct node{
  40. int sum;
  41. node *ls,*rs;
  42. node(){sum=0,ls=rs=NULL;}
  43. }*rt;
  44. void mdf(node *&u,int l,int r,int lp,int rp,int val){
  45. if(!u) u=new(node);
  46. if(lp<=l && r<=rp){
  47. u->sum+=val;
  48. return;
  49. }
  50. int mid=l+r>>1;
  51. if(lp<=mid) mdf(u->ls,l,mid,lp,rp,val);
  52. if(rp>mid) mdf(u->rs,mid+1,r,lp,rp,val);
  53. }
  54. int qry(node *u,int l,int r,int pos){
  55. if(!u) return 0;
  56. if(l==r) return u->sum;
  57. int mid=l+r>>1,ret=u->sum;
  58. if(pos<=mid) ret+=qry(u->ls,l,mid,pos);
  59. else ret+=qry(u->rs,mid+1,r,pos);
  60. return ret;
  61. }
  62. public:
  63. void mdf(int lp,int rp,int val){mdf(rt,0,n,lp,rp,val);}
  64. int qry(int pos){return qry(rt,0,n,pos);}
  65. }plus[MAXN],minus[MAXN];
  66. inline void addE(int u,int v){
  67. static int cnt;
  68. ed[++cnt]=(line){v,he[u]};
  69. he[u]=cnt;
  70. }
  71. void DFS(int u,int fa){
  72. de[u]=de[fa]+1;
  73. dfn[++dfn[0]]=u;
  74. pos[u]=dfn[0];
  75. for(int i=he[u],v;i;i=ed[i].nex){
  76. v=ed[i].to;
  77. if(v!=fa){
  78. DFS(v,u);
  79. dfn[++dfn[0]]=u;
  80. }
  81. }
  82. }
  83. void get_grt(int u,int fa){
  84. static int max_subT_sz[MAXN]={INT_MAX};
  85. sz[u]=1,max_subT_sz[u]=0;
  86. for(int i=he[u],v;i;i=ed[i].nex){
  87. v=ed[i].to;
  88. if(!use[v] && v!=fa){
  89. get_grt(v,u);
  90. sz[u]+=sz[v];
  91. max_subT_sz[u]=max(max_subT_sz[u],sz[v]);
  92. }
  93. }
  94. max_subT_sz[u]=max(max_subT_sz[u],sum_sz-sz[u]);
  95. if(max_subT_sz[u]<max_subT_sz[grt]) grt=u;
  96. }
  97. void treeDC(int u){
  98. use[u]=true;
  99. for(int i=he[u],v;i;i=ed[i].nex){
  100. v=ed[i].to;
  101. if(!use[v]){
  102. grt=0,sum_sz=sz[v];
  103. get_grt(v,0);
  104. fa[grt]=u;
  105. treeDC(grt);
  106. }
  107. }
  108. }
  109. inline int cal_dis(int u,int v){
  110. return de[u]+de[v]-(de[st.LCA(u,v)]<<1);
  111. }
  112. inline int qry(int u){
  113. int ret=plus[u].qry(0);
  114. for(int now=u,dis;fa[now];now=fa[now]){
  115. dis=cal_dis(fa[now],u);
  116. ret+=plus[fa[now]].qry(dis);
  117. ret-=minus[now].qry(dis);
  118. }
  119. return ret;
  120. }
  121. inline void mdf(int u,int k,int w){
  122. plus[u].mdf(0,k,w);
  123. for(int now=u,dis;fa[now];now=fa[now]){
  124. dis=cal_dis(fa[now],u);
  125. if(dis>k) continue;
  126. plus[fa[now]].mdf(0,k-dis,w);
  127. minus[now].mdf(0,k-dis,w);
  128. }
  129. }
  130. int main(){
  131. int m;
  132. scanf("%d%d",&n,&m);
  133. for(int i=1,u,v;i<n;++i){
  134. scanf("%d%d",&u,&v);
  135. addE(u,v),addE(v,u);
  136. }
  137. DFS(1,0);
  138. st.init(dfn,dfn[0]);
  139. sum_sz=n;
  140. get_grt(1,0);
  141. treeDC(grt);
  142. char opt;
  143. for(int i=1,x,d,w;i<=m;++i){
  144. scanf("\n%c%d",&opt,&x);
  145. if(opt=='Q') printf("%d\n",qry(x));
  146. else{
  147. scanf("%d%d",&d,&w);
  148. mdf(x,d,w);
  149. }
  150. }
  151. return 0;
  152. }

3.[ZJOI 2015] 幻想乡战略游戏

代码:

  1. #include <cstdio>
  2. #include <algorithm>
  3. #include <cstring>
  4. #include <climits>
  5. #include <cmath>
  6. #include <vector>
  7. using std::max;
  8. using std::swap;
  9. using std::vector;
  10. const int MAXN=1e5+5;
  11. int grt,sum_sz;
  12. int he[MAXN],fa[MAXN],sz[MAXN];
  13. int lv[MAXN],dis[MAXN][19];
  14. int val_sum[MAXN];
  15. long long cost_sum[MAXN],tofa_cost[MAXN];
  16. bool use[MAXN];
  17. vector<int> T[MAXN],DCT[MAXN];
  18. struct line{int to,nex,w;}ed[MAXN<<1];
  19. inline void addE(int u,int v,int w){
  20. static int cnt;
  21. ed[++cnt]=(line){v,he[u],w};
  22. he[u]=cnt;
  23. }
  24. void get_grt(int u,int fa){
  25. static int max_subT_sz[MAXN]={INT_MAX};
  26. sz[u]=1,max_subT_sz[u]=0;
  27. for(int i=he[u],v;i;i=ed[i].nex){
  28. v=ed[i].to;
  29. if(!use[v] && v!=fa){
  30. get_grt(v,u);
  31. sz[u]+=sz[v];
  32. max_subT_sz[u]=max(max_subT_sz[u],sz[v]);
  33. }
  34. }
  35. max_subT_sz[u]=max(max_subT_sz[u],sum_sz-sz[u]);
  36. if(max_subT_sz[u]<max_subT_sz[grt]) grt=u;
  37. }
  38. void DFS(int u,int fa,int lv){
  39. for(int i=he[u],v;i;i=ed[i].nex){
  40. v=ed[i].to;
  41. if(!use[v] && v!=fa){
  42. dis[v][lv]=dis[u][lv]+ed[i].w;
  43. DFS(v,u,lv);
  44. }
  45. }
  46. }
  47. void treeDC(int u,int lv){
  48. use[u]=true;
  49. ::lv[u]=lv;
  50. DFS(u,0,lv);
  51. for(int i=he[u],v;i;i=ed[i].nex){
  52. v=ed[i].to;
  53. if(use[v]) continue;
  54. T[u].push_back(v);
  55. grt=0,sum_sz=sz[v];
  56. get_grt(v,0);
  57. fa[grt]=u;
  58. DCT[u].push_back(grt);
  59. treeDC(grt,lv+1);
  60. }
  61. }
  62. inline void mdf(int u,int w){
  63. for(int now=u;now;now=fa[now]){
  64. val_sum[now]+=w;
  65. cost_sum[now]+=(long long)w*dis[u][lv[now]];
  66. tofa_cost[now]+=(long long)w*dis[u][lv[fa[now]]];
  67. }
  68. }
  69. inline long long qry(int u){
  70. long long ret=0;
  71. for(int now=u;now;now=fa[now]){
  72. ret+=cost_sum[now];
  73. ret-=tofa_cost[now];
  74. ret+=(long long)val_sum[now]*(dis[u][lv[now]]-dis[u][lv[fa[now]]]);
  75. }
  76. return ret;
  77. }
  78. long long solve(int u){
  79. long long ret=qry(u);
  80. for(int i=0,lim=T[u].size();i<lim;++i){
  81. if(ret>qry(T[u][i]))
  82. return solve(DCT[u][i]);
  83. }
  84. return ret;
  85. }
  86. int main(){
  87. int n,q;
  88. scanf("%d%d",&n,&q);
  89. for(int i=1,u,v,w;i<n;++i){
  90. scanf("%d%d%d",&u,&v,&w);
  91. addE(u,v,w),addE(v,u,w);
  92. }
  93. sum_sz=n;
  94. get_grt(1,0);
  95. int grt=::grt;
  96. treeDC(grt,1);
  97. for(int i=1,u,e;i<=q;++i){
  98. scanf("%d%d",&u,&e);
  99. mdf(u,e);
  100. printf("%lld\n",solve(grt));
  101. }
  102. return 0;
  103. }

可持久化重心树:[HNOI 2015] 开店

代码:

  1. #include <cstdio>
  2. #include <algorithm>
  3. #include <climits>
  4. using std::max;
  5. using std::swap;
  6. using std::sort;
  7. using std::lower_bound;
  8. using std::upper_bound;
  9. const int MAXN=150005;
  10. int n;
  11. struct monster{
  12. int age,id;
  13. monster(int _age=0,int _id=0):age(_age),id(_id){}
  14. bool operator <(const monster &that)const{
  15. return age<that.age;
  16. }
  17. static bool cmp_age(const monster &a,const monster &b){
  18. return a.age<b.age;
  19. }
  20. }devil[MAXN];
  21. class pDCT{
  22. private:
  23. int grt,sum_sz;
  24. int he[MAXN],sz[MAXN];
  25. int lv[MAXN],dis[MAXN][20],son_id[MAXN][20];
  26. bool use[MAXN];
  27. struct line{int to,nex,w;}ed[MAXN<<1];
  28. void get_grt(int u,int fa){
  29. static int max_subT_sz[MAXN]={INT_MAX};
  30. sz[u]=1,max_subT_sz[u]=0;
  31. for(int i=he[u],v;i;i=ed[i].nex){
  32. v=ed[i].to;
  33. if(!use[v] && v!=fa){
  34. get_grt(v,u);
  35. sz[u]+=sz[v];
  36. max_subT_sz[u]=max(max_subT_sz[u],sz[v]);
  37. }
  38. }
  39. max_subT_sz[u]=max(max_subT_sz[u],sum_sz-sz[u]);
  40. if(max_subT_sz[u]<max_subT_sz[grt]) grt=u;
  41. }
  42. void DFS(int u,int fa,int lv){
  43. for(int i=he[u],v;i;i=ed[i].nex){
  44. v=ed[i].to;
  45. if(!use[v] && v!=fa){
  46. son_id[v][lv]=son_id[u][lv];
  47. dis[v][lv]=dis[u][lv]+ed[i].w;
  48. DFS(v,u,lv);
  49. }
  50. }
  51. }
  52. void treeDC(int u,int lv){
  53. use[u]=true;
  54. this->lv[u]=lv;
  55. for(int i=he[u],v,idx=0;i;i=ed[i].nex){
  56. v=ed[i].to;
  57. if(!use[v]){
  58. son_id[v][lv]=idx++;
  59. dis[v][lv]=ed[i].w;
  60. DFS(v,0,lv);
  61. grt=0,sum_sz=sz[v];
  62. get_grt(v,0);
  63. treeDC(grt,lv+1);
  64. }
  65. }
  66. }
  67. public:
  68. void addE(int u,int v,int w){
  69. static int cnt;
  70. ed[++cnt]=(line){v,he[u],w};
  71. he[u]=cnt;
  72. }
  73. void build(){
  74. sum_sz=n;
  75. get_grt(1,0);
  76. treeDC(grt,1);
  77. }
  78. private:
  79. struct node{
  80. int node_cnt;
  81. long long dis_sum,tofa_dis;
  82. node *s[3];
  83. node(){
  84. dis_sum=0;
  85. tofa_dis=node_cnt=0;
  86. s[0]=s[1]=s[2]=&Null;
  87. }
  88. node(node *u){*this=*u;}
  89. }*rt[MAXN];
  90. static node Null;
  91. public:
  92. pDCT(){rt[0]=&Null;}
  93. private:
  94. void ist(node *pre,node *&now,int u,int lv){
  95. now=new node(pre);
  96. now->dis_sum+=dis[u][lv];
  97. now->tofa_dis+=dis[u][lv-1];
  98. ++now->node_cnt;
  99. if(lv!=this->lv[u])
  100. ist(pre->s[son_id[u][lv]],now->s[son_id[u][lv]],u,lv+1);
  101. }
  102. long long qry(node *now,int u,int lv){
  103. if(now==&Null) return 0;
  104. long long ret=0;
  105. ret+=now->dis_sum;
  106. ret-=now->tofa_dis;
  107. ret+=(long long)now->node_cnt*(dis[u][lv]-dis[u][lv-1]);
  108. if(lv!=this->lv[u])
  109. ret+=qry(now->s[son_id[u][lv]],u,lv+1);
  110. return ret;
  111. }
  112. long long qry(int now,int u){return qry(rt[now],u,1);}
  113. public:
  114. void ist(int pre,int now,int u){ist(rt[pre],rt[now],u,1);}
  115. long long qry(int l,int r,int u){return qry(r,u)-qry(l-1,u);}
  116. }T;
  117. pDCT::node pDCT::Null;
  118. inline void prepare(){
  119. sort(devil+1,devil+n+1,monster::cmp_age);
  120. for(int i=1;i<=n;++i)
  121. T.ist(i-1,i,devil[i].id);
  122. }
  123. inline void find_his(int &l,int &r){
  124. l=lower_bound(devil+1,devil+n+1,monster(l))-devil;
  125. r=upper_bound(devil+1,devil+n+1,monster(r))-devil-1;
  126. }
  127. int main(){
  128. int q,a;
  129. scanf("%d%d%d",&n,&q,&a);
  130. for(int i=1;i<=n;++i){
  131. scanf("%d",&devil[i].age);
  132. devil[i].id=i;
  133. }
  134. for(int i=1,u,v,w;i<n;++i){
  135. scanf("%d%d%d",&u,&v,&w);
  136. T.addE(u,v,w),T.addE(v,u,w);
  137. }
  138. T.build();
  139. prepare();
  140. long long lastans=0;
  141. for(int i=1,u,l,r;i<=q;++i){
  142. scanf("%d%d%d",&u,&l,&r);
  143. l=(l+lastans)%a;
  144. r=(r+lastans)%a;
  145. if(l>r) swap(l,r);
  146. find_his(l,r);
  147. lastans=T.qry(l,r,u);
  148. printf("%lld\n",lastans);
  149. }
  150. return 0;
  151. }

替罪羊树思想维护重心树:[WC 2014] 紫荆花之恋

代码:

  1. #include <cstdio>
  2. #include <algorithm>
  3. #include <cstdlib>
  4. #include <set>
  5. #include <stack>
  6. using std::swap;
  7. using std::set;
  8. using std::stack;
  9. const int MAXN=100005,MOD=1e9;
  10. int r[MAXN];
  11. class Treap{
  12. #define ls s[0]
  13. #define rs s[1]
  14. public:
  15. struct node{
  16. int val,key,cnt,sz;
  17. node *s[2];
  18. node(){val=key=cnt=sz=0; s[0]=s[1]=Null;}
  19. node(int _val):val(_val),key(rand()){
  20. cnt=sz=1,ls=rs=Null;
  21. }
  22. void* operator new(size_t){
  23. node *ret;
  24. if(mem_cur>mem_pool) ret=&*(mem_cur--);
  25. else ret=mem_bin.top(),mem_bin.pop();
  26. return ret;
  27. }
  28. void operator delete[](void *u){ //删除子树
  29. if(((node*)u)->ls!=Null) delete[](((node*)u)->ls);
  30. if(((node*)u)->rs!=Null) delete[](((node*)u)->rs);
  31. mem_bin.push((node*)u);
  32. }
  33. void upd(){sz= ls->sz + rs->sz + cnt;}
  34. }*rt;
  35. static node *Null;
  36. Treap(){rt=Null;}
  37. private:
  38. static node mem_pool[MAXN*100];
  39. static node *mem_cur;
  40. static stack<node*> mem_bin;
  41. private:
  42. static node* rot(node *u,bool lr){
  43. node *son=u->s[lr];
  44. u->s[lr]=son->s[lr^1];
  45. son->s[lr^1]=u;
  46. u->upd(),son->upd();
  47. return son;
  48. }
  49. static node* maintain(node *u,bool lr){
  50. if(u->key > u->s[lr]->key)
  51. u=rot(u,lr);
  52. return u;
  53. }
  54. public:
  55. static void ist(node *&u,int val){
  56. if(u==Null){
  57. u= new node(val);
  58. return;
  59. }
  60. if(u->val == val) ++u->cnt;
  61. else{
  62. bool lr=(val > u->val);
  63. ist(u->s[lr],val);
  64. u=maintain(u,lr);
  65. }
  66. u->upd();
  67. }
  68. void ist(int val){ist(rt,val);}
  69. void clear(){
  70. if(rt!=Null) delete[](rt);
  71. rt=Null;
  72. }
  73. int size(){return rt->sz;}
  74. int lt_cnt(int val){ //小于val的值的个数
  75. node *u=rt; int ret=0;
  76. while(u!=Null){
  77. if(u->val <= val){
  78. ret+= u->ls->sz + u->cnt;
  79. u=u->rs;
  80. }
  81. else u=u->ls;
  82. }
  83. return ret;
  84. }
  85. #undef ls
  86. #undef rs
  87. };
  88. Treap::node Treap::mem_pool[MAXN*100];
  89. Treap::node *Treap::Null=&mem_pool[0];
  90. Treap::node *Treap::mem_cur=Treap::mem_pool+(MAXN*100)-1;
  91. stack<Treap::node*> Treap::mem_bin;
  92. class SG_dync_DCT{
  93. //pre T ↓
  94. private:
  95. int he[MAXN];
  96. int anc[17][MAXN],dis[MAXN],de[MAXN];
  97. struct line{int to,nex,w;}ed[MAXN<<1];
  98. void addE(int u,int v,int w){
  99. static int cnt;
  100. ed[++cnt]=(line){v,he[u],w};
  101. he[u]=cnt;
  102. }
  103. void prepare_LCA(int u,int fa){ //计算新加入的点的倍增数组
  104. anc[0][u]=fa;
  105. for(int i=1;i<17;++i)
  106. anc[i][u]=anc[i-1][anc[i-1][u]];
  107. }
  108. int LCA(int u,int v){
  109. if(de[u]<de[v]) swap(u,v);
  110. for(int d=de[u]-de[v],i=0;d;d>>=1,++i){
  111. if(d&1) u=anc[i][u];
  112. }
  113. if(u==v) return v;
  114. for(int i=16;i>=0;--i){
  115. if(anc[i][u]!=anc[i][v])
  116. u=anc[i][u],v=anc[i][v];
  117. }
  118. return anc[0][u];
  119. }
  120. int cal_dis(int u,int v){
  121. return dis[u]+dis[v]-(dis[LCA(u,v)]<<1);
  122. }
  123. public:
  124. int ist(int u,int fa,int w){ //新加入u点
  125. addE(u,fa,w),addE(fa,u,w);
  126. de[u]=de[fa]+1,dis[u]=dis[fa]+w;
  127. prepare_LCA(u,fa);
  128. return upd(u,fa);
  129. }
  130. //DCT ↓
  131. private:
  132. static const double ALPHA;
  133. int idx; //访问标号
  134. int use[MAXN],vis[MAXN]; //用不用该点,该点这次重构是否访问过
  135. int sz[MAXN];
  136. int fa[MAXN]; //上层重心
  137. set<int> dct[MAXN]; //重心树
  138. Treap plus[MAXN],minus[MAXN]; //和之前的动态点分治套路一样
  139. void DFS_del(int u){ //删除重心树的u的子树的treap和边
  140. //因为只有这里是正常下去遍历整棵子树的,
  141. //所以只能在这里标记等会可以到的点
  142. //后面标记会gg,在treeDC里遍历是跳跃的,
  143. //且这里只重建了一部分,没有重建的部分没有访问标记,
  144. //遍历着会绕上去到不该重建的地方
  145. use[u]=idx;
  146. plus[u].clear();
  147. for(set<int>::iterator iter=dct[u].begin();iter!=dct[u].end();++iter){
  148. minus[*iter].clear();
  149. DFS_del(*iter);
  150. }
  151. dct[u].clear();
  152. }
  153. int DFS_sz(int u,int fa){
  154. sz[u]=1;
  155. for(int i=he[u],v;i;i=ed[i].nex){
  156. v=ed[i].to;
  157. if(vis[v]!=idx && use[v]==idx && v!=fa)
  158. sz[u]+=DFS_sz(v,u);
  159. }
  160. return sz[u];
  161. }
  162. int get_grt(int u,int fa,int lim){
  163. for(int i=he[u],v;i;i=ed[i].nex){
  164. v=ed[i].to;
  165. if(vis[v]!=idx && use[v]==idx && v!=fa){
  166. if(sz[v]>lim) return get_grt(v,u,lim);
  167. }
  168. }
  169. return u;
  170. }
  171. void DFS_ist(int u,int fa,int dis,Treap::node *&tp_rt){ //和3730那些一个套路
  172. Treap::ist(tp_rt,dis-r[u]);
  173. for(int i=he[u],v;i;i=ed[i].nex){
  174. v=ed[i].to;
  175. if(vis[v]!=idx && use[v]==idx && v!=fa)
  176. DFS_ist(v,u,dis+ed[i].w,tp_rt);
  177. }
  178. }
  179. int treeDC(int u){ //这里由于有加点操作,treeDC()和之前略有不同
  180. u=get_grt(u,0,DFS_sz(u,0)>>1);
  181. vis[u]=idx;
  182. DFS_ist(u,0,0,plus[u].rt);
  183. Treap::node *minus_rt;
  184. for(int i=he[u],v;i;i=ed[i].nex){
  185. v=ed[i].to;
  186. if(vis[v]!=idx && use[v]==idx){
  187. minus_rt=Treap::Null;
  188. DFS_ist(v,u,ed[i].w,minus_rt);
  189. v=treeDC(v);
  190. this->fa[v]=u;
  191. dct[u].insert(v);
  192. minus[v].rt=minus_rt;
  193. }
  194. }
  195. return u;
  196. }
  197. void rebuild(int u){
  198. ++idx;
  199. int fa=this->fa[u];
  200. if(fa) dct[fa].erase(u);
  201. DFS_del(u);
  202. //这个treap是针对fa而算的,所以可以保留
  203. //treeDC里的做法同理
  204. Treap::node *minus_rt=minus[u].rt;
  205. minus[u].rt=Treap::Null;
  206. u=treeDC(u);
  207. this->fa[u]=fa;
  208. if(fa) dct[fa].insert(u);
  209. minus[u].rt=minus_rt;
  210. }
  211. bool bal(int u){
  212. return plus[u].size()<ALPHA*plus[fa[u]].size()+0.5;
  213. }
  214. void maintain(int u){
  215. int cur=0;
  216. for(;fa[u];u=fa[u]){
  217. if(!bal(u)) cur=fa[u];
  218. }
  219. if(cur) rebuild(cur);
  220. }
  221. int upd(int u,int fa){ //更新:计算u所带来的影响
  222. this->fa[u]=fa;
  223. dct[fa].insert(u);
  224. int ret=0;
  225. for(int now=u,r=::r[u],fa,dis;now;now=fa){
  226. fa=this->fa[now];
  227. if(fa){
  228. dis=cal_dis(u,fa);
  229. ret+=plus[fa].lt_cnt(r-dis);
  230. ret-=minus[now].lt_cnt(r-dis);
  231. minus[now].ist(dis-r);
  232. }
  233. plus[now].ist(cal_dis(u,now)-r);
  234. }
  235. maintain(u);
  236. return ret;
  237. }
  238. }DCT;
  239. const double SG_dync_DCT::ALPHA=0.88;
  240. int main(){
  241. srand(125);
  242. int n;
  243. scanf("%*d%d",&n);
  244. long long lastans=0;
  245. for(int i=1,fa,w;i<=n;++i){
  246. scanf("%d%d%d",&fa,&w,&r[i]);
  247. fa^=lastans%MOD;
  248. lastans+=DCT.ist(i,fa,w);
  249. printf("%lld\n",lastans);
  250. }
  251. return 0;
  252. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注