题目:http://acm.hdu.edu.cn/showproblem.php?pid=5511

题意:割一些边使得无向图变成不连通的,并且恰好割了两条给定生成树上的边。满足非树边两段一定在给定生成树的根的不同子树里。求最小边数。

看了题解。

  一直考虑割出来的是树上的连通块之类的。

  其实考虑讨论那两条树边的关系。

  1.两条边是祖先--后代关系。

    答案就是它们之间夹着的连通块伸出去的非树边条数+2。所以两条边离得越近越好。

    那么就是一个点的父亲边+该点父亲的父亲边。O(n)枚举即可。

    注意1号点没有父亲边。

  2.两条边不是祖先--后代关系。

    那么两条边引导了两个子树。答案就是这两个子树伸出去的非树边条数 - 两个子树相互的非树边条数*2 + 2 。

    然后又不太会了。

    其实考虑答案形如 d[ x ] + d[ y ] - 2*cnt( x, y ) ,那么枚举 x ,用线段树维护 d[ y ] - 2*cnt( x, y ) 的最小值即可。注意1号点不能参与。

    那么就是线段树合并得到 cnt( ) ,再加入当前根 cr 的贡献,就是 cr 连出去的点 y , y 到父亲的链上的值都 - 2 。

    还要把 cr 的位置设成 INF 。

  动态开点。每个点的初值是 “只考虑 d[ ] 不考虑 cnt ,区间最小值” 。这个可以预处理。借鉴了 Claris 的写法,把该值记在以 cr << 1 , cr<<1|1 为结构得到的线段树角标上。

  注意如果没有左孩子或右孩子之类的,调用的是上述初值而不是 0 或 INF 。

  直接线段树合并,空间不行。考虑像 dsu on tree 一样,每个点继承其重孩子的线段树。线段树合并之后,轻孩子的线段树节点都删掉。这样同时又 log 个线段树,空间可行。

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<vector>
  5. #define pb push_back
  6. #define ls Ls[cr]
  7. #define rs Rs[cr]
  8. using namespace std;
  9. int rdn()
  10. {
  11. int ret=;bool fx=;char ch=getchar();
  12. while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
  13. while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
  14. return fx?ret:-ret;
  15. }
  16. int Mx(int a,int b){return a>b?a:b;}
  17. int Mn(int a,int b){return a<b?a:b;}
  18. const int N=2e4+,M=N*,INF=1e6+;
  19. int n,m,hd[N],xnt,to[N<<],nxt[N<<],rd[N],ans;
  20. int tim,dfn[N],dy[N],top[N],son[N],siz[N],fa[N],dep[N];
  21. int rt[N],tot,Ls[M],Rs[M],mn[M],tg[M];
  22. int w[N<<],dlpl[M],dtop;
  23. vector<int> vt[N];
  24. void init()
  25. {
  26. xnt=; for(int i=;i<=n;i++)hd[i]=;
  27. tim=tot=dtop=;
  28. for(int i=;i<=n;i++)vector<int>().swap(vt[i]);
  29. for(int i=;i<=n;i++)son[i]=;///
  30. for(int i=;i<=n;i++)rt[i]=;///
  31. for(int i=;i<=n*;i++)w[i]=INF;
  32. }
  33. void add(int x,int y)
  34. {to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;}
  35. void ini_build(int l,int r,int cr)
  36. {
  37. if(l==r)
  38. {if(dy[l]==)w[cr]=INF;else w[cr]=rd[dy[l]];return;}
  39. int mid=l+r>>;
  40. ini_build(l,mid,cr<<);
  41. ini_build(mid+,r,cr<<|);
  42. w[cr]=Mn(w[cr<<],w[cr<<|]);
  43. }
  44. void dfs(int cr,int f)
  45. {
  46. fa[cr]=f; dep[cr]=dep[f]+; siz[cr]=;
  47. rd[cr]=vt[cr].size();
  48. for(int i=hd[cr],v;i;i=nxt[i])
  49. if((v=to[i])!=f)
  50. {
  51. dfs(v,cr); rd[cr]+=rd[v]; siz[cr]+=siz[v];
  52. if(siz[v]>siz[son[cr]])son[cr]=v;
  53. }
  54. if(cr==)return;//
  55. for(int i=hd[cr],v;i;i=nxt[i])
  56. if((v=to[i])!=f)
  57. ans=Mn(ans,rd[cr]-rd[v]);
  58. }
  59. void dfsx(int cr,int f)
  60. {
  61. dfn[cr]=++tim; dy[tim]=cr;
  62. if(son[cr]){ top[son[cr]]=top[cr];dfsx(son[cr],cr);}
  63. for(int i=hd[cr],v;i;i=nxt[i])
  64. if((v=to[i])!=f&&v!=son[cr])
  65. { top[v]=v; dfsx(v,cr);}
  66. }
  67. int nwnd(int id)
  68. {
  69. int cr;
  70. if(dtop)cr=dlpl[dtop--]; else cr=++tot;
  71. ls=rs=tg[cr]=; mn[cr]=w[id]; return cr;
  72. }
  73. void del(int x){ dlpl[++dtop]=x;}
  74. void pshp(int cr,int id)//if!!!
  75. {
  76. if(ls)mn[cr]=mn[ls]; else mn[cr]=w[id<<];
  77. if(rs)mn[cr]=Mn(mn[cr],mn[rs]);
  78. else mn[cr]=Mn(mn[cr],w[id<<|]);
  79. }
  80. void pshd(int cr,int id)
  81. {
  82. if(!tg[cr])return; int w=tg[cr]; tg[cr]=;
  83. if(!ls)ls=nwnd(id<<); if(!rs)rs=nwnd(id<<|);
  84. tg[ls]+=w; tg[rs]+=w; mn[ls]+=w; mn[rs]+=w;
  85. }
  86. void mdfy(int l,int r,int &cr,int id,int p)
  87. {
  88. if(!cr)cr=nwnd(id); if(l==r){mn[cr]=INF;return;}
  89. int mid=l+r>>; pshd(cr,id);
  90. if(p<=mid)mdfy(l,mid,ls,id<<,p);
  91. else mdfy(mid+,r,rs,id<<|,p);
  92. pshp(cr,id);
  93. }
  94. void add(int l,int r,int &cr,int id,int L,int R)
  95. {
  96. if(!cr)cr=nwnd(id);
  97. if(l>=L&&r<=R){tg[cr]-=;mn[cr]-=;return;}
  98. int mid=l+r>>; pshd(cr,id);
  99. if(L<=mid)add(l,mid,ls,id<<,L,R);
  100. if(mid<R)add(mid+,r,rs,id<<|,L,R);
  101. pshp(cr,id);
  102. }
  103. void mrg(int l,int r,int &cr,int id,int v)
  104. {
  105. if(!cr){cr=v;return;} if(!v)return;
  106. if(l==r)
  107. {
  108. if(mn[cr]==INF||mn[v]==INF)mn[cr]=INF;
  109. else {mn[cr]+=mn[v]; mn[cr]-=rd[dy[l]];}
  110. del(v); return;
  111. }
  112. int mid=l+r>>; pshd(cr,id); pshd(v,id);
  113. mrg(l,mid,ls,id<<,Ls[v]);
  114. mrg(mid+,r,rs,id<<|,Rs[v]);
  115. pshp(cr,id); del(v);
  116. }
  117. void solve(int cr)
  118. {
  119. if(son[cr]){ solve(son[cr]); rt[cr]=rt[son[cr]];}
  120. for(int i=hd[cr],v;i;i=nxt[i])
  121. if((v=to[i])!=fa[cr]&&v!=son[cr])
  122. {
  123. solve(v); mrg(,n,rt[cr],,rt[v]);
  124. }
  125. if(cr==)return;////!!!
  126. mdfy(,n,rt[cr],,dfn[cr]);
  127. for(int i=,lm=vt[cr].size();i<lm;i++)
  128. {
  129. int x=vt[cr][i];
  130. while(top[x]!=)
  131. {
  132. add(,n,rt[cr],,dfn[top[x]],dfn[x]);
  133. x=fa[top[x]];
  134. }
  135. if(x>)add(,n,rt[cr],,,dfn[x]);///no 1
  136. }
  137. ans=Mn(ans,rd[cr]+mn[rt[cr]]);
  138. }
  139. int main()
  140. {
  141. int T=rdn();
  142. for(int t=;t<=T;t++)
  143. {
  144. n=rdn();m=rdn(); init();
  145. for(int i=,u,v;i<n;i++)
  146. {
  147. u=rdn();v=rdn();add(u,v);add(v,u);
  148. }
  149. for(int i=n,u,v;i<=m;i++)
  150. {
  151. u=rdn();v=rdn();
  152. vt[u].pb(v); vt[v].pb(u);
  153. }
  154. ans=INF; dfs(,);
  155. top[]=; dfsx(,);
  156. ini_build(,n,); solve();
  157. printf("Case #%d: %d\n",t,ans+);
  158. }
  159. return ;
  160. }

hdu 5511 Minimum Cut-Cut——分类讨论思想+线段树合并的更多相关文章

  1. HDU 1394 Minimum Inversion Number(最小逆序数 线段树)

    Minimum Inversion Number [题目链接]Minimum Inversion Number [题目类型]最小逆序数 线段树 &题意: 求一个数列经过n次变换得到的数列其中的 ...

  2. hdu 5266 pog loves szh III(lca + 线段树)

    I - pog loves szh III Time Limit:6000MS     Memory Limit:131072KB     64bit IO Format:%I64d & %I ...

  3. 2017多校第8场 HDU 6133 Army Formations 线段树合并

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6133 题意:给你一棵n个节点的二叉树,每个节点有一个提交任务的时间,每个节点总的提交任务的罚时为:提交 ...

  4. HDU 2795 Billboard(宣传栏贴公告,线段树应用)

    HDU 2795 Billboard(宣传栏贴公告,线段树应用) ACM 题目地址:HDU 2795 Billboard 题意:  要在h*w宣传栏上贴公告,每条公告的高度都是为1的,并且每条公告都要 ...

  5. HDU 6665 Calabash and Landlord (分类讨论)

    2019 杭电多校 8 1009 题目链接:HDU 6665 比赛链接:2019 Multi-University Training Contest 8 Problem Description Cal ...

  6. [CERC2017]Intrinsic Interval——扫描线+转化思想+线段树

    [CERC2017]Intrinsic Interval https://www.luogu.org/blog/ywycasm/solution-p4747# 这种“好的区间”,见得还是比较多的了. ...

  7. HDU - 6521 Party (SYSU校赛K题)(线段树)

    题目链接 题意:n个人排成一列,一开始他们互不认识,每次选[l,r]上的人开party,使他们互相认识,求出每次party之后新互相认识的人的对数. 思路:把“互相认识”变成单向连边,只考虑左边的人对 ...

  8. 题解 HDU 3698 Let the light guide us Dp + 线段树优化

    http://acm.hdu.edu.cn/showproblem.php?pid=3698 Let the light guide us Time Limit: 5000/2000 MS (Java ...

  9. 【HDU4630 No Pain No Game】 dp思想+线段树的离线操作

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4630 题意:给你n个数据范围在[1,n]中的数,m个操作,每个操作一个询问[L,R],让你求区间[L, ...

随机推荐

  1. 测开之路一百零二:jquery元素操作

    jquery对元素操作,获取/替换文本(.text()).html(.html()).属性(.attr()).值(.val()) html代码 text() 根据标签获取文本值 同一个标签下筛选明细 ...

  2. c#处理bin文件

    1. fs.Position  写入的位置,从哪个位置开始写 fs.Write(byte1,0,byte1.Length); byte1写入的byte[], 写入内容从第几位开始取,length取多长 ...

  3. python实现建立udp通信

    实现代码如下: #udp协议通信import socket,timeclass UdpConnect: def get_udp(self,ip,port,message): #建立udp连接 myso ...

  4. Spring Boot 之 springcache的使用

    一.开启 springcache,启动类添加 @EnableCaching 注解 @SpringBootApplication @EnableCaching public class Gatherin ...

  5. Java中StringHelp

    import java.util.Collection; import java.util.Map; import java.util.UUID; public class StringHelper ...

  6. 将字符串转换成C#认可的对象(有键值对的对象)

    var resobj = Newtonsoft.Json.JsonConvert.DeserializeObject<Newtonsoft.Json.Linq.JArray>(result ...

  7. 多线程02-Join

        ; i < ; i++)             {                 Console.WriteLine(i);             }             Co ...

  8. [Python3] 009 字符串:给你们看看我的内置方法 第一弹

    目录 前言 如何查看 python3 中和 str 有关的方法 字符串方法 1. capitalize() 2. casefold() 3. center(width) 4. count(sub[, ...

  9. Spring事务管理之几种方式实现事务(转)

    一:事务认识 大家所了解的事务Transaction,它是一些列严密操作动作,要么都操作完成,要么都回滚撤销.Spring事务管理基于底层数据库本身的事务处理机制.数据库事务的基础,是掌握Spring ...

  10. 被我误解的max_connect_errors

    第一节  什么是max_connect_errors 一开始接触这个参数的时候,感觉他和max_connections的含义差不多,字面意思简单明了,这个参数的含义是最大连接错误数,翻翻mysql的文 ...