设$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.

    文章转自 http://www.cnblogs.com/ggjucheng/archive/2013/01/13/2858385.html sort sort 命令对 File 参数指定的文件中的行排 ...

  2. [转]linux sort,uniq,cut,wc命令详解

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

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

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

  4. linux sort,uniq,cut,wc,tr命令详解

    sort是在Linux里非常常用的一个命令,对指定文件进行排序.去除重复的行 sort 命令对 File 参数指定的文件中的行排序,并将结果写到标准输出.如果 File 参数指定多个文件,那么 sor ...

  5. Linux之 sort,uniq,cut,wc命令详解

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

  6. Linux Shell脚本入门--cut命令

    Linux Shell脚本入门--cut命令 cut cut 命令可以从一个文本文件或者文本流中提取文本列. cut语法 [root@www ~]# cut -d'分隔字符' -f fields &l ...

  7. Ubuntu 14.10 下sort,uniq,cut,wc命令详解

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

  8. 文本处理命令--cut、sort、join

    声明:下面介绍的只是命令的常用选项,如果需要详细了解命令全部细节,需要参考其他的资料. 一.cut cut是一个选取命令,就是将一段数据经过分析,取出我们想要的.一般来说,选取信息通常是针对“行”来进 ...

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

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

随机推荐

  1. Idea 12配置SPring MVC 和Tomcat Server

    配置Spring 1. 添加idea插件 都选上了.也许有用! 2. 添加Spring库 下载spring,添加java库,指向spring库的目录: 配置tomcat Server 1. 安装tom ...

  2. 实现用VB.Net/(C#)开发K/3 BOS 插件的真正可行方法

    转了这一篇文章,原来一直想用C#做k3的插件开发,vb没有C#用的爽呀,这篇文章写与2011年,看来我以前没有认真去找这个方法呀. https://blog.csdn.net/chzjxgd/arti ...

  3. 运维基础——Zabbix 设置Redis监控

    https://blog.csdn.net/xundh/article/details/77604357

  4. [转] Immutable 常用API简介

    本文主要整理了Immutable.js常用API的使用. Immutable 是什么? 关于Immutable的定义,官方文档是这样说的: Immutable data encourages pure ...

  5. nodejs 2017

    1.  nodejs函数 path()  nodejs全局变量 __dirname a.js // 运行 node a.js var path = require('path'); console.l ...

  6. 调整LaTeX文档页面的大小

    看下面这张图片便一目了然!!!       借助 geometry 包,可以很方便地调整页面大小,常用的参数如图所示,这些参数都可以通过LateX支持的单位(mm, cm, pt, in)去重新设置. ...

  7. lrzsz linix 远程文件传输工具。

    安装方法 #yum install lrzsz -y 使用方法 #rz -y 上传指定文档到当前目录

  8. VMware安装操作系统提示 " Intel VT-x 处于禁用状态"解决方法

    VMWARE WORKSTATION 在安装64为操作系统(kali)报错,报错内容为:“已将该虚拟机配置为使用 64 位客户机操作系统.但是,无法执行 64 位操作. 此主机支持 Intel VT- ...

  9. Fiddler教程--简介

    1.开发环境host配置 自己修改系统的host来回挺麻烦的 2.前后的接口调试 3.线上bugfix 4.性能分析和优化 5.等等... 工作原理 一个代理服务器 地址改为 127.0.0.1:88 ...

  10. es6 promise对象

    function next(){ return new Promise( function( resolve, reject ){ var num =7 // Math.floor( Math.ran ...