设$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. jquery 笔记 点击周围区域子类隐藏,点击子类内部的信息 不隐藏

    zilei.click(ev){ var e = ev||event; e.stopPropagation(); //dosomething } $(document).click(function( ...

  2. Scrapy项目创建以及目录详情

    Scrapy项目创建已经目录详情 一.新建项目(scrapy startproject) 在开始爬取之前,必须创建一个新的Scrapy项目.进入自定义的项目目录中,运行下列命令: PS C:\scra ...

  3. nodejs 2017

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

  4. ajax请求头加Token时发生的跨域(CORS)请求问题

    首先描述下问题:需求是在请求头中加入token,我在ajax请求数据时添加了请求头‘Authorization’字段,并添加了响应的token值,在请求数据的时候浏览器报错如下: Request he ...

  5. 分享几个在线生成网址二维码的API接口

    现在很多大网站都有这样的一个功能,使用手机扫描一下网页上的二维码便可快速在手机上访问网站.想要实现这样的功能其实很简单,下面麦布分享几个在线生成网址二维码的API接口.都是采用http协议接口,无需下 ...

  6. C语言整理——文件系统和文件访问

    标准C中规定了文件系统的访问和对文件本身的访问.不管是windows系统或者是泛unix系统,都实现了这些接口.在了解这些知识后,跨平台编程也将非常容易. 对文件系统的访问接口有: chdrive() ...

  7. Python_迭代器

    迭代器:迭代器里的元素读一个丢一个,不能回退,不能用下标访问 x.__next__():迭代器里唯一的方法,只读下一个 d = iter(['Presly', 'is', 'lovely', ]) p ...

  8. 查看windows电脑CPU核心数,线程数

    在Windows中,在cmd命令中输入“wmic”,然后在出现的新窗口中输入“cpu get *”即可查看物理CPU数.CPU核心数.线程数.其中,  Name:表示物理CPU数  NumberOfC ...

  9. 关系网络数据可视化:3. 案例:公司职员关系图表 & 导演演员关系网络可视化

    1. 公司职员关系图表 节点和边界数据 节点是指每个节点本身的数据,代表公司职工的名称:属性(Country).分类(Category)和地区(Region,给每个节点定义的属性数据).文件必须是.c ...

  10. bind注意事项(传引用参数的时候)

    默认情况下,bind的那些不是占位符的参数被拷贝到bind返回的可调用对象中. 当需要把对象传到bind中的参数中时,需要使用ref或者cref. 例如: #include<iostream&g ...