设$d[x]$表示端点位于$x$子树内部的非树边条数,那么有两种情况:

$1.$割去的两条树边$(x,fa[x]),(y,fa[y])$中,$x$是$y$的祖先,那么此时需要割去的非树边数量为$d[x]-d[y]$。

显然固定$x$之后$y$越靠上越好,因此$y$一定是$x$的儿子,枚举即可,时间复杂度$O(n)$。

$2.$一般化的情况,此时$x\neq y$,需要割去的非树边数量为$d[x]+d[y]-2cnt(x,y)$,其中$cnt(x,y)$表示一端在$x$子树中,另一端在$y$子树中的非树边数量。

枚举$x$,对于每个$y$维护$d[y]-2cnt(x,y)$。

首先需要把$x$子树的$cnt$合并,然后对于一条端点恰好为$x$的非树边$(x,u)$,需要把$u$到根路径上的$d-2cnt$都减去$2$。

树链剖分+线段树维护即可,时间复杂度$O(m\log^2n)$。

直接实现的话,空间复杂度也为$O(m\log^2n)$,不能承受。

每次先dfs重儿子,将$x$的重儿子的线段树直接作为$x$的线段树,然后依次与轻儿子合并,同时将废弃线段树节点回收利用。

如此一来,只有经过轻边时,才会多开一棵动态开点的线段树,那么一共只会同时存在$O(\log n)$棵线段树。

每棵线段树就算开满也只有$O(n)$的空间,因此空间复杂度为$O(n\log n)$。

#include<cstdio>
const int N=20010,M=100010,E=1200000;
int Case,cas,n,m,i,x,y,g[N],v[N<<1],nxt[N<<1],ed,ans;
int d[N],G[N],V[M<<1],NXT[M<<1],ED;
int f[N],size[N],son[N],top[N],loc[N],dfn,q[N];
int T[N],l[E],r[E],tag[E],val[E],pool[E],cur,w[66000];
inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
inline void ADD(int x,int y){d[x]++;V[++ED]=y;NXT[ED]=G[x];G[x]=ED;}
inline void umin(int&a,int b){a>b?(a=b):0;}
inline int min(int a,int b){return a<b?a:b;}
void dfs(int x){size[x]=1;for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]){f[v[i]]=x;dfs(v[i]);size[x]+=size[v[i]],d[x]+=d[v[i]];if(size[v[i]]>size[son[x]])son[x]=v[i];}if(x>1)for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x])umin(ans,d[x]-d[v[i]]);
}
void dfs2(int x,int y){loc[x]=++dfn;top[x]=y;if(son[x])dfs2(son[x],y);for(int i=g[x];i;i=nxt[i])if(v[i]!=son[x]&&v[i]!=f[x])dfs2(v[i],v[i]);
}
void build(int x,int a,int b){if(a==b){w[x]=q[a];return;}int mid=(a+b)>>1;build(x<<1,a,mid),build(x<<1|1,mid+1,b);w[x]=min(w[x<<1],w[x<<1|1]);
}
inline int newnode(int o){int x=pool[cur--];l[x]=r[x]=tag[x]=0;val[x]=w[o];return x;
}
inline void tag1(int x,int p){tag[x]+=p;val[x]+=p;}
inline void pb(int x,int o){if(tag[x]){if(!l[x])l[x]=newnode(o<<1);if(!r[x])r[x]=newnode(o<<1|1);tag1(l[x],tag[x]),tag1(r[x],tag[x]),tag[x]=0;}
}
inline void up(int x,int o){if(!l[x])l[x]=newnode(o<<1);if(!r[x])r[x]=newnode(o<<1|1);val[x]=min(val[l[x]],val[r[x]]);
}
void change(int&x,int o,int a,int b,int c,int d,int p){if(!x)x=newnode(o);if(c<=a&&b<=d){tag1(x,p);return;}pb(x,o);int mid=(a+b)>>1;if(c<=mid)change(l[x],o<<1,a,mid,c,d,p);if(d>mid)change(r[x],o<<1|1,mid+1,b,c,d,p);up(x,o);
}
inline void chain(int&T,int x){while(top[x]!=1)change(T,1,1,n,loc[top[x]],loc[x],-2),x=f[top[x]];if(x>1)change(T,1,1,n,2,loc[x],-2);
}
int merge(int x,int y,int o,int a,int b){if(!x||!y)return x+y;if(a==b)tag[x]+=tag[y];else{pb(x,o),pb(y,o);int mid=(a+b)>>1;l[x]=merge(l[x],l[y],o<<1,a,mid);r[x]=merge(r[x],r[y],o<<1|1,mid+1,b);up(x,o);}pool[++cur]=y;return x;
}
void clear(int x,int a,int b){if(!x)return;pool[++cur]=x;if(a==b)return;int mid=(a+b)>>1;clear(l[x],a,mid),clear(r[x],mid+1,b);
}
void dfs3(int x){if(son[x])dfs3(son[x]),T[x]=T[son[x]];for(int i=g[x];i;i=nxt[i])if(v[i]!=son[x]&&v[i]!=f[x])dfs3(v[i]),T[x]=merge(T[x],T[v[i]],1,1,n);if(x==1)return;for(int i=G[x];i;i=NXT[i])chain(T[x],V[i]);change(T[x],1,1,n,loc[x],loc[x],M);umin(ans,d[x]+val[T[x]]);change(T[x],1,1,n,loc[x],loc[x],-M);
}
int main(){for(i=1;i<E;i++)pool[++cur]=i;scanf("%d",&Case);for(cas=1;cas<=Case;cas++){scanf("%d%d",&n,&m);ans=M;for(i=1;i<n;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x);for(;i<=m;i++)scanf("%d%d",&x,&y),ADD(x,y),ADD(y,x);dfs(1),dfs2(1,1);for(i=1;i<=n;i++)q[loc[i]]=d[i];build(1,1,n);dfs3(1);printf("Case #%d: %d\n",cas,ans+2);clear(T[1],1,n);for(ed=ED=dfn=0,i=1;i<=n;i++)g[i]=d[i]=G[i]=f[i]=size[i]=son[i]=T[i]=0;}return 0;
}

  

HDU5511 : Minimum Cut-Cut相关推荐

  1. Linux中sort,uniq,cut,wc命令详解

    Linux中sort,uniq,cut,wc命令详解 来源:hellodev 本文主要对Linux中sort,uniq,cut,wc这4个命令的使用方法进行了详细说明,希望对你有所帮助. sort s ...

  2. Linux常用基本命令(cut)

    cut命令 作用:从文件的每一行剪切字节,字符或者字段,类似与编程语言中的字符串截取函数 格式:cut [option] [file] -b:仅显示行中指定直接范围的内容: -c:仅显示行中指定范围的 ...

  3. 数据流重定向和管道命令, grep, tr,sort, wc, cut,split,tee,sleep(shell 02)

    主要内容 1.标准输入输出和错误 2.管道命令和 grep, tr,sort, wc, cut,split,tee,sleep 标准输入输出和错误 标准输入(stdin) 是指令数据的输入,代码为0, ...

  4. linux——编写Shell脚本常用命令:diff、patch、cut、sort、uniq、、||、test、tr

    diff 和 patch 命令帮助:diff –help | patch –help diff命令在最简单的情况下,比较给定的两个文件的不同.如果使用"-"代替"文件&q ...

  5. Linux Shell脚本编程--cut命令

    cut cut命令可以从一个文本文件或者文本流中提取文本列. cut语法 [root@www ~]# cut -d'分隔字符' -f fields <==用于有特定分隔字符 [root@www ...

  6. Linux文本处理命令:cut grep awk sed printf

    行 grep : 善于利用字符进行获取内容 针对于行的   [选项] [模式][文件]  选项规定内容样式 模式规定内容 sed:修改器   善于使用行数进行操作 针对于行的 列 cut :   cu ...

  7. linux sort,uniq,cut,wc命令详解

    linux sort,uniq,cut,wc命令详解 sort sort 命令对 File 参数指定的文件中的行排序,并将结果写到标准输出.如果 File 参数指定多个文件,那么 sort 命令将这些 ...

  8. Linux中sort、uniq、cut、wc命令详解

    sort sort 命令对 File 参数指定的文件中的行排序,并将结果写到标准输出.如果 File 参数指定多个文件,那么 sort 命令将这些文件连接起来,并当作一个文件进行排序. sort语法[ ...

  9. Linux文本截取命令cut​笔记

    在Linux日常运维中有时候需要对文本内容进行处理,比如文本截取功能,这个时候可以使用Linux下的cut命令对格式有规范的文本进行截取. 语法格式:cut -f指定的列 -d '分隔符号' 用法介绍 ...

最新文章

  1. Maven的配置文件pom.xml
  2. 第六集 MSF构思阶段项目团队的组建
  3. java 字节数组作用_这段java代码中字节数组b起到了什么作用?
  4. 筹款の不定方程(洛谷P4956题题解,Java语言描述)
  5. Android-动画简介
  6. 安卓 App 库存系统开发 基础版本
  7. 群辉 NAS 配置 iSCSI 存储
  8. 精进1-职业价值 by采铜
  9. Buuctf --hellow world
  10. 不选主元的矩阵三角分解法
  11. Github建个人静态网页
  12. 【Security】可信网络连接
  13. WinAPI入门: 第一个标准Win32窗口程序 [改进详细注释版]
  14. 车辆检测(视觉分类器训练)
  15. 一个很好用的gif动态图控件:GifImageView
  16. spd软件系统的发展-医用耗材管理系统功能优势发展及分析
  17. Cookie Session跨站无法共享问题(单点登录解决方案)
  18. Hotel California 加州旅馆
  19. 使用计算机辅助绘图需要注意哪些问题,计算机辅助制图一.ppt
  20. 【windows】组装电脑笔记

热门文章

  1. Jquery实现点击页面发送弹幕效果
  2. Centos7下安装Docker(详细安装教程、傻瓜式安装)
  3. 【数据竞赛】“达观杯”文本智能处理挑战赛2
  4. 有没有必要开项目周会
  5. linux的gromacs模拟分子运动,分子动力学技术交流---gromacsamber
  6. Java如何让小球随机运动_用java模拟两球的随机运动及碰撞
  7. MATLAB观察系统响应,基于MATLAB的系统的时域响应分析精选.doc
  8. 神策数据《银行4.0数字化运营体系构建的方法与实践》正式发布
  9. Swagger生成的接口需要权限验证的处理方法
  10. 生产者消费者问题Java三种实现