设$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. webpack学习笔记--压缩代码

    浏览器从服务器访问网页时获取的 JavaScript.CSS 资源都是文本形式的,文件越大网页加载时间越长. 为了提升网页加速速度和减少网络传输流量,可以对这些资源进行压缩. 压缩的方法除了可以通过 ...

  2. 无法连接ssh,fatal: daemon() failed: No such device

    今天发现一个服务器的sshd无法启动,查看/var/log/secure里发现:fatal: daemon() failed: No such device 解决办法: rm /dev/null /d ...

  3. ubuntu下的“用vim打开中文乱码,用cat打开正常显示”的解决方法

    转载 系统环境:ubuntu10.04 vim gvim完全安装 问题:终端下vim中的汉字为乱码,网上搜索了一些解决方案.但是奇怪的是,这些方法都不能实现gvim的菜单和文中汉字,终端vim下的文中 ...

  4. [转] Mongoose简要API

    Mongoose是在node.js环境下对mongodb进行便捷操作的对象模型工具 因此,要使用mongoose,则必须安装node.js环境以及mongodb数据库.mongoose使mongodb ...

  5. 【转】利用 selenium 的 webdrive 驱动 headless chrome

    1.参考 使用 headless chrome进行测试 2.概念 Headless模式解决了什么问题: 自动化工具例如 selenium 利用有头浏览器进行测试,面临效率和稳定性的影响,所以出现了 H ...

  6. Centos7防火墙常用命令及mask锁定不能添加端口问题

    一.开放端口 sudo firewall-cmd --zone=public --add-port=3000/tcp --permanent sudo firewall-cmd --reload 二. ...

  7. Office 2010 word无法创建工作文件 请检查临时环境变量 的解决办法

    Office 2010 word无法创建工作文件 请检查临时环境变量 的解决办法 http://hi.baidu.com/netshen/item/207fd935d452e0e9df2221c9 如 ...

  8. Python_冒泡排序

    从小到大的排序:(最前面的数和一步步和后面的数比较,如果大于则交换,如果不大于则继续循环) 方法1: data = [65, 1, 45, 77, 3, 9, 43, 23, 7, 53, 213, ...

  9. 初识Python.day2

    一. python运算符 算数运算符  比较运算符 赋值运算符 逻辑运算符 成员运算符 二. Python基础数据类型 1. python字符串总结 # 首字母变大写 # a1 = "jiu ...

  10. Python学习(七) —— 装饰器、迭代器、生成器

    一.装饰器(decorator) 1.装饰器的本质是闭包函数,作用:在不改变函数的调用方式的情况下,给函数的前后添加新的功能 #装饰器的固定结构 def warpper(func): #定义装饰器函数 ...