【2019.7.10】树上差分 杂[LCA 倍增][树上差分 点差分 边差分]

迷南。 2021-11-17 15:44 397阅读 0赞

多用于记录树上节点被经过的次数,记录某条边被经过的次数的时候

点差分

P3128 [USACO15DEC]最大流Max Flow

s−−>t求这条路径上的点被经过的次数找到他们的LCA 需要让 cnts++ cntt++ cntlca-- cntfa(lca)--

  1. /*
  2. id:lxyyyy
  3. 树上差分 3128
  4. */
  5. #include<iostream>
  6. #include<cstdio>
  7. #include<queue>
  8. #include<cstring>
  9. #include<cmath>
  10. #include<stack>
  11. #include<algorithm>
  12. using namespace std;
  13. #define ll long long
  14. #define rg register
  15. #define lson o<<1
  16. #define rson o<<1|1
  17. const int N=50000+5,M=200000+5,inf=0x3f3f3f3f,P=19650827;
  18. int n,k,cnt[N],f[N][25],dep[N],ans=0;
  19. template <class t>void rd(t &x){
  20. x=0;int w=0;char ch=0;
  21. while(!isdigit(ch)) w|=ch=='-',ch=getchar();
  22. while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
  23. x=w?-x:x;
  24. }
  25. int head[N],tot=0;
  26. struct edge{
  27. int v,nxt;}e[N<<1];
  28. void add(int u,int v){
  29. e[++tot]=(edge){v,head[u]};head[u]=tot;
  30. }
  31. void dfs(int u,int fa){
  32. dep[u]=dep[fa]+1;
  33. f[u][0]=fa;
  34. for(int i=1;i<=20;++i){
  35. if(dep[u]<(1<<i)) break;
  36. f[u][i]=f[f[u][i-1]][i-1];
  37. }
  38. for(int i=head[u];i;i=e[i].nxt){
  39. if(e[i].v==fa) continue;
  40. dfs(e[i].v,u);
  41. }
  42. }
  43. int LCA(int a,int b){
  44. if(dep[a]>dep[b]) swap(a,b);
  45. for(int i=20;i>=0;--i){
  46. if(dep[f[b][i]]<dep[a]) continue;
  47. b=f[b][i];
  48. }
  49. if(b==a) return a;
  50. for(int i=20;i>=0;--i){
  51. if(f[a][i]==f[b][i]) continue;
  52. a=f[a][i],b=f[b][i];
  53. }
  54. return f[a][0];
  55. }
  56. void dfs2(int u,int fa){
  57. for(int i=head[u],v;i;i=e[i].nxt){
  58. v=e[i].v;
  59. if(v==fa) continue;
  60. dfs2(v,u);
  61. cnt[u]+=cnt[v];
  62. }
  63. }
  64. int main(){
  65. rd(n),rd(k);
  66. for(int i=1,u,v;i<n;++i) rd(u),rd(v),add(u,v),add(v,u);
  67. int s,t;
  68. dfs(1,0);
  69. while(k--){
  70. rd(s),rd(t);
  71. int lca=LCA(s,t);
  72. ++cnt[s],++cnt[t],--cnt[lca],--cnt[f[lca][0]];
  73. }
  74. dfs2(1,0);
  75. for(int i=1;i<=n;++i) ans=max(ans,cnt[i]);
  76. printf("%d",ans);
  77. return 0;
  78. }

最大流 点差分

P3258 [JLOI2014]松鼠的新家

要注意它从顺序上2~n-1个点都重复走了一次 而最终到最后一个点时它不用算一次 所以将顺序上2~n的点的次数依次减一

  1. /*
  2. id:lxyyyy
  3. 树上差分 3128
  4. */
  5. #include<iostream>
  6. #include<cstdio>
  7. #include<queue>
  8. #include<cstring>
  9. #include<cmath>
  10. #include<stack>
  11. #include<algorithm>
  12. using namespace std;
  13. #define ll long long
  14. #define rg register
  15. #define lson o<<1
  16. #define rson o<<1|1
  17. const int N=300000+5,M=200000+5,inf=0x3f3f3f3f,P=19650827;
  18. int n,a[N],cnt[N],f[N][25],dep[N],ans=0;
  19. template <class t>void rd(t &x){
  20. x=0;int w=0;char ch=0;
  21. while(!isdigit(ch)) w|=ch=='-',ch=getchar();
  22. while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
  23. x=w?-x:x;
  24. }
  25. int head[N],tot=0;
  26. struct edge{
  27. int v,nxt;}e[N<<1];
  28. void add(int u,int v){
  29. e[++tot]=(edge){v,head[u]};head[u]=tot;
  30. }
  31. void dfs(int u,int fa){
  32. dep[u]=dep[fa]+1;
  33. f[u][0]=fa;
  34. for(int i=1;i<=20;++i){
  35. if(dep[u]<(1<<i)) break;
  36. f[u][i]=f[f[u][i-1]][i-1];
  37. }
  38. for(int i=head[u];i;i=e[i].nxt){
  39. if(e[i].v==fa) continue;
  40. dfs(e[i].v,u);
  41. }
  42. }
  43. int LCA(int a,int b){
  44. if(dep[a]>dep[b]) swap(a,b);
  45. for(int i=20;i>=0;--i){
  46. if(dep[f[b][i]]<dep[a]) continue;
  47. b=f[b][i];
  48. }
  49. if(a==b) return a;
  50. for(int i=20;i>=0;--i){
  51. if(f[b][i]==f[a][i]) continue;
  52. a=f[a][i],b=f[b][i];
  53. }
  54. return f[a][0];
  55. }
  56. void dfs2(int u,int fa){
  57. for(int i=head[u],v;i;i=e[i].nxt){
  58. v=e[i].v;
  59. if(v==fa) continue;
  60. dfs2(v,u);
  61. cnt[u]+=cnt[v];
  62. }
  63. }
  64. int main(){
  65. rd(n);
  66. for(int i=1;i<=n;++i) rd(a[i]);
  67. for(int i=1,u,v;i<n;++i) rd(u),rd(v),add(u,v),add(v,u);
  68. dfs(1,0);
  69. for(int i=2;i<=n;++i){
  70. int lca=LCA(a[i-1],a[i]);
  71. ++cnt[a[i-1]],++cnt[a[i]],--cnt[lca],--cnt[f[lca][0]];
  72. }
  73. dfs2(1,0);
  74. for(int i=2;i<=n;++i) --cnt[a[i]];
  75. for(int i=1;i<=n;++i) printf("%d\n",cnt[i]);
  76. return 0;
  77. }

松鼠的新家 点差分

边差分

用cf[i]表示i点到它父亲的这条边 关于边的差分lca不包括在里面 所以考虑u->lca这条链 则使cf[u]++ cf[lca]—

同理lca->v cf[v]++ cf[lca]— 则总的为cf[u]++ cf[v]++ cf[lca]-2

POJ 3417**loj暗的连锁**

主边构成树 附加边将其所连的两个点之间成为一个环 主边,附加边各砍一刀问有多少种方案使得该图成两部分

  1. 砍一个未被覆盖过的主边 后一次操作无论砍哪个附加边都可以
  2. 砍一个被覆盖一次的主边 则后一次只能砍覆盖它的这个附加边
  3. 砍一个被覆盖两次以上的主边无论再怎么砍都不能将其分为两部分

所以进行一遍边差分 然后枚举判断

我会说我又一次在读入s和t的时候用的while(m—)吗??

  1. /*
  2. id:lxyyyy
  3. 树上差分 poj3417 边差分
  4. */
  5. #include<iostream>
  6. #include<cstdio>
  7. #include<queue>
  8. #include<cstring>
  9. #include<cmath>
  10. #include<stack>
  11. #include<algorithm>
  12. using namespace std;
  13. #define ll long long
  14. #define rg register
  15. #define lson o<<1
  16. #define rson o<<1|1
  17. const int N=100000+5,M=200000+5,inf=0x3f3f3f3f,P=19650827;
  18. int n,m,cnt[N],f[N][25],dep[N],ans=0;
  19. template <class t>void rd(t &x){
  20. x=0;int w=0;char ch=0;
  21. while(!isdigit(ch)) w|=ch=='-',ch=getchar();
  22. while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
  23. x=w?-x:x;
  24. }
  25. int head[N],tot=0;
  26. struct edge{
  27. int v,nxt;}e[N<<1];
  28. void add(int u,int v){
  29. e[++tot]=(edge){v,head[u]};head[u]=tot;
  30. }
  31. void dfs(int u,int fa){
  32. dep[u]=dep[fa]+1;
  33. f[u][0]=fa;
  34. for(rg int i=1;i<=20;++i){
  35. if(dep[u]<(1<<i)) break;
  36. f[u][i]=f[f[u][i-1]][i-1];
  37. }
  38. for(int i=head[u];i;i=e[i].nxt){
  39. if(e[i].v==fa) continue;
  40. dfs(e[i].v,u);
  41. }
  42. }
  43. int LCA(int a,int b){
  44. if(dep[a]>dep[b]) swap(a,b);
  45. for(rg int i=20;i>=0;--i){
  46. if(dep[f[b][i]]<dep[a]) continue;
  47. b=f[b][i];
  48. }
  49. if(b==a) return a;
  50. for(rg int i=20;i>=0;--i){
  51. if(f[a][i]==f[b][i]) continue;
  52. a=f[a][i],b=f[b][i];
  53. }
  54. return f[a][0];
  55. }
  56. void dfs2(int u,int fa){
  57. for(int i=head[u];i;i=e[i].nxt){
  58. if(e[i].v==fa) continue;
  59. dfs2(e[i].v,u);
  60. cnt[u]+=cnt[e[i].v];
  61. }
  62. }
  63. int main(){
  64. // freopen("yam1.in","r",stdin);
  65. rd(n),rd(m);
  66. for(int i=1,u,v;i<n;++i) rd(u),rd(v),add(u,v),add(v,u);
  67. int s,t,lca;
  68. dfs(1,0);
  69. for(int i=1;i<=m;++i){
  70. rd(s),rd(t);
  71. lca=LCA(s,t);
  72. ++cnt[s],++cnt[t],cnt[lca]-=2;
  73. }
  74. dfs2(1,0);
  75. for(int i=1;i<=n;++i){
  76. if(!cnt[i]&&i!=1) ans+=m;
  77. if(cnt[i]==1) ++ans;
  78. }
  79. printf("%d",ans);
  80. return 0;
  81. }

POJ3417

【luogu2680】【noip2015】 运输计划 [LCA 树上差分 边差分][二分]

发表评论

表情:
评论列表 (有 0 条评论,397人围观)

还没有评论,来说两句吧...

相关阅读

    相关

    概念 对于一个数组a\[n\],有m次操作,都是对区间\[l,r\]加上k,完事后输出数组 在知道第一个数a\[1\]的情况下,如果我们知道后面的数与前一个数的差值p,