• 洛谷 P3128 [USACO15DEC] Max Flow P


    题目链接:P3128 [USACO15DEC] Max Flow P - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)


    前置知识,LCA模板

    洛谷 P3379 【模板】最近公共祖先(LCA)-CSDN博客

    读题注意

    从隔间s运输到隔间t,和从隔间t运输到隔间s,都没区别,因为加的压力是一样的,所以这是一个无向图。

    并且只有N个节点和N-1条边,所以是一棵树。

    分析

    如果每次都去遍历[s,t]这个区间去给每个节点都加上1,那么复杂度肯定会T飞出去,因为是区间修改考虑用差分维护,但是这个是树,改变思路可以将节点s压力+1节点t压力+1lca(s,t)压力-2。

    发现直接对lca减二并不符合运输情况,考虑递归回溯性质改成lca(s,t)压力-1lca(s,t)父节点压力-1

    这样一边回溯一边累计答案就可以了。

    AC代码(倍增求LCA+树上差分)

    1. #include
    2. using namespace std;
    3. const int N=5e4+5;
    4. int n,k,p[N],ans=INT_MIN,d[N];
    5. int f[N][20],lg[N];
    6. vector<int>e[N];
    7. bitsetvis;
    8. inline int read(){
    9. int x=0;char c=getchar();
    10. while(c<48 or c>57)c=getchar();
    11. while(c>=48 and c<=57)x=(x<<3)+(x<<1)+(c xor 48),c=getchar();
    12. return x;
    13. }
    14. int lca(int x,int y){
    15. if(d[x]swap(x,y);
    16. while(d[x]>d[y])x=f[x][lg[d[x]-d[y]]-1];
    17. if(x==y)return x;
    18. for(int i=lg[d[x]];i>=0;--i)
    19. if(f[x][i]!=f[y][i]){
    20. x=f[x][i];
    21. y=f[y][i];
    22. }
    23. return f[x][0];
    24. }
    25. void dfs(int now,int fa){
    26. if(vis[now])return;
    27. vis[now]=true;
    28. d[now]=d[fa]+1;
    29. f[now][0]=fa;
    30. for(int i=1;i<=lg[d[now]];++i)
    31. f[now][i]=f[f[now][i-1]][i-1];
    32. for(auto i:e[now])dfs(i,now);
    33. }
    34. void dfs_ans(int now){
    35. if(vis[now])return;
    36. vis[now]=true;
    37. for(auto i:e[now]){
    38. if(!vis[i]){//一定要加这一句,不然下面p[now]会累计父节点的值
    39. dfs_ans(i);
    40. p[now]+=p[i];
    41. }
    42. }
    43. ans=max(ans,p[now]);
    44. }
    45. int main(){
    46. n=read(),k=read();
    47. for(int i=1,x,y;i<=n-1;++i){
    48. x=read(),y=read();
    49. e[x].push_back(y);
    50. e[y].push_back(x);
    51. }
    52. for(int i=1;i<=n;++i){
    53. lg[i]=log(i)/log(2)+1;
    54. }
    55. dfs(1,1);
    56. for(int i=1,s,t;i<=k;++i){
    57. s=read(),t=read();
    58. int fa=lca(s,t);
    59. p[s]++,p[t]++,p[fa]--,p[f[fa][0]]--;
    60. }
    61. vis.reset();
    62. dfs_ans(1);
    63. cout<
    64. return 0;
    65. }

    这里面有个坑,用子节点往父节点传递信息的时候,如果是STL开的邻接表一定一定要记得在循环里面加一下父节点的判断,不然debug找两年   :(

    包括传递子节点数量这种树上dp也一样。

    既然倍增LCA能过,那么不得不试一下用线段树维护欧拉序求LCA了

    查询都是log级别,只是线段树的常数会大一点,代码会多一点。

    AC代码(线段树维护欧拉序+树上差分)

    1. #include
    2. using namespace std;
    3. const int N=5e4+5;
    4. int n,k,p[N],res,f[N],idx[N<<1],st[N<<3],oula[N<<1],oulan,d[N];
    5. vector<int>e[N];
    6. bitsetvis;
    7. inline int read(){
    8. int x=0;char c=getchar();
    9. while(c<48 or c>57)c=getchar();
    10. while(c>=48 and c<=57)x=(x<<3)+(x<<1)+(c xor 48),c=getchar();
    11. return x;
    12. }
    13. void dfs(int x){
    14. if(vis[x])return;
    15. vis[x]=true;
    16. oula[++oulan]=x;
    17. if(!idx[x])idx[x]=oulan;
    18. for(auto i:e[x]){
    19. if(!vis[i]){//用STL写的千万别忘了加这个,不然无向图会累计父节点
    20. f[i]=x;//最好所有dfs都加这个判断。
    21. d[i]=d[x]+1;
    22. dfs(i);
    23. oula[++oulan]=x;
    24. if(!idx[x])idx[x]=oulan;
    25. }
    26. }
    27. }
    28. void build(int l,int r,int i){
    29. if(l==r){
    30. st[i]=oula[l];
    31. return;
    32. }
    33. int mid=(l+r)>>1;
    34. build(l,mid,i<<1);
    35. build(mid+1,r,i<<1|1);
    36. st[i]=d[st[i<<1]]1|1]]?st[i<<1]:st[i<<1|1];
    37. }
    38. int lca(int l,int r,int i,int x,int y){
    39. int ans=0;
    40. if(l>=x and r<=y)return st[i];
    41. int mid=(l+r)>>1;
    42. if(x<=mid){
    43. int t=lca(l,mid,i<<1,x,y);
    44. if(d[t]
    45. }
    46. if(y>mid){
    47. int t=lca(mid+1,r,i<<1|1,x,y);
    48. if(d[t]
    49. }
    50. return ans;
    51. }
    52. void dfs_res(int x){
    53. if(vis[x])return;
    54. vis[x]=true;
    55. for(auto i:e[x]){
    56. if(!vis[i]){
    57. dfs_res(i);
    58. p[x]+=p[i];
    59. }
    60. }
    61. res=max(p[x],res);
    62. }
    63. int main(){
    64. n=read(),k=read();
    65. for(int i=1,x,y;i<=n-1;++i){
    66. x=read(),y=read();
    67. e[x].push_back(y);
    68. e[y].push_back(x);
    69. }
    70. dfs(1);
    71. build(1,oulan,1);
    72. d[0]=INT_MAX;
    73. for(int i=1,s,t;i<=k;++i){
    74. s=read(),t=read();
    75. int l=idx[s],r=idx[t],LCA;
    76. if(l>r)swap(l,r);
    77. LCA=lca(1,oulan,1,l,r);
    78. p[s]++,p[t]++,p[LCA]--,p[f[LCA]]--;
    79. }
    80. vis.reset();
    81. dfs_res(1);
    82. cout<
    83. return 0;
    84. }

  • 相关阅读:
    基于物联网表计的综合能源管理方案-安科瑞黄安南
    CSS滚动条详解(::-webkit-scrollbar )
    精通 Verilog HDL 设计之编码风格(1)引言
    Linux系统-gedit的使用
    DNS入门学习:什么是TTL值?如何设置合适的TTL值?
    C#学习相关系列之Linq常用方法---排序(一)
    ElasticSearch join连接查询
    Vue3.2弹窗表单多功能组件的封装
    Android本地文件操作
    26栈和队列-简单实践
  • 原文地址:https://blog.csdn.net/qq_17807067/article/details/134449647