题目:https://loj.ac/problem/2339

两棵树的话,可以用 CTSC2018 暴力写挂的方法,边分治+虚树。O(nlogn)。

考虑怎么在这个方法上再加一棵树。发现很难弄。

看了看题解,发现两棵树还有别的做法。

  就是要最大化 d1[ x ] + d2[ x ] + d1[ y ] + d2[ y ] - 2*d1[ lca1(x,y) ] - 2*d2[ lca2(x,y) ] ,考虑在第一棵树 T1 上 dfs 地枚举 lca1 ,那么考虑的答案就是 T1 上在当前点 cr 的不同子树里的 x 和 y 。

  考虑 cr 的之前子树 v1 和当前子树 v2 怎么合并。 v1 和 v2 都记录着自己子树里的答案的两个点 x 和 y 。

  似乎根据树的直径证明的类似方法可以得知 cr 的 x 就是 v1 和 v2 的 x 中的一个, cr 的 y 就是 v1 和 v2 的 y 中的一个。

  所以把两个 x 和两个 y 组合一下,看看谁的 d1[ x ] + d2[ x ] + d1[ y ] + d2[ y ] - 2*d2[ lca2(x,y) ] 最小,谁就是 cr 的 x 和 y 。

  做完 cr 之后,因为要换 lca1 了,所以先贡献一下答案,就是把 cr 记录的 x 和 y 按上面要最大化的那个式子贡献给答案。

  只要 RMQ 求 lca 就可以 O(n) 。

所以三棵树就是在这个两棵树的做法上给第三棵树套一个边分治。

就是在当前边分治的情况下,枚举 lca1 ,式子变成最大化 d1[ x ] + d2[ x ] + d3[ x ] + d1[ y ] + d2[ y ] + d2[ y ] - 2*d1[ lca1(x,y) ] - 2*d2[ lca2(x,y) ] + tw,其中 d1[ ] , d2[ ] 是在树 T1 和 T2 上的带权深度,d3[ ] 是在 T3 上到分治中心边的距离, tw 是分治中心边的权值。

枚举 lca1 之后,不仅 x 和 y 不能在 T1 上 lca1 的同一棵子树中,且 x 和 y 还得分别是 T3 的分治中心两边的点,所以 T2 上 DP 的时候,每个点要记两对 ( x , y ) ,表示 T3 两边的直径。

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<vector>
  5. #define ll long long
  6. #define pil pair<int,ll>
  7. #define pb push_back
  8. #define mkp make_pair
  9. using namespace std;
  10. ll rdn()
  11. {
  12. ll ret=;bool fx=;char ch=getchar();
  13. while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
  14. while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
  15. return fx?ret:-ret;
  16. }
  17. ll Mx(ll a,ll b){return a>b?a:b;}
  18. ll Mn(ll a,ll b){return a<b?a:b;}
  19. const int N=2e5+,K=; const ll INF=1e18;
  20. int n,tn,hd[N],xnt=,to[N<<],nxt[N<<];ll w[N<<];
  21. int siz[N],mn,Rt,lx[N]; vector<pil> vt[N];
  22. ll d1[N],d2[N],d3[N],ans;
  23. namespace T3{
  24. int hd[N],xnt,to[N<<],nxt[N<<];ll w[N<<];
  25. int dep[N],bg[N],en[N],tim,st[N][K],lg[N],bin[K+];
  26. void add(int x,int y,ll z)
  27. {
  28. to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;w[xnt]=z;
  29. to[++xnt]=x;nxt[xnt]=hd[y];hd[y]=xnt;w[xnt]=z;
  30. }
  31. void ini_dfs(int cr,int fa)
  32. {
  33. bg[cr]=++tim; st[tim][]=cr;
  34. for(int i=hd[cr],v;i;i=nxt[i])
  35. if((v=to[i])!=fa)
  36. {
  37. dep[v]=dep[cr]+; d3[v]=d3[cr]+w[i];
  38. ini_dfs(v,cr); st[++tim][]=cr;/////
  39. }
  40. en[cr]=tim;
  41. }
  42. void init()
  43. {
  44. ll z;
  45. for(int i=,u,v;i<n;i++)
  46. u=rdn(),v=rdn(),z=rdn(),add(u,v,z);
  47. ini_dfs(,); int tn=n<<;
  48. for(int i=;i<=tn;i++)lg[i]=lg[i>>]+;
  49. bin[]=;for(int i=;i<=lg[tn];i++)bin[i]=bin[i-]<<;
  50. for(int t=;t<=lg[tn];t++)
  51. for(int i=;i+bin[t]-<=tn;i++)
  52. {
  53. int u=st[i][t-], v=st[i+bin[t-]][t-];
  54. st[i][t]=(dep[u]<dep[v]?u:v);
  55. }
  56. }
  57. int get_lca(int x,int y)
  58. {
  59. if(bg[x]>bg[y])swap(x,y); int d=lg[en[y]-bg[x]+];
  60. int c1=st[bg[x]][d], c2=st[en[y]-bin[d]+][d];
  61. int ret=dep[c1]<dep[c2]?c1:c2;
  62. return ret;
  63. }
  64. }
  65. namespace T2{
  66. int hd[N],xnt,to[N<<],nxt[N<<];ll w[N<<];
  67. int tim,a[N],ta[N],lca[N],tlca[N],dep[N],sta[N],top;
  68. struct Node{
  69. int x,y;ll w;
  70. Node(int x=,int y=,ll w=):x(x),y(y),w(w) {}
  71. }dp[N][];
  72. void add(int x,int y,ll z)
  73. {
  74. to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;w[xnt]=z;
  75. to[++xnt]=x;nxt[xnt]=hd[y];hd[y]=xnt;w[xnt]=z;
  76. }
  77. void ini_dfs(int cr,int fa)
  78. {
  79. while(top&&dep[sta[top]]>=dep[cr])top--;
  80. a[++tim]=cr; lca[tim]=sta[top]; sta[++top]=cr;
  81. for(int i=hd[cr],v;i;i=nxt[i])
  82. if((v=to[i])!=fa)
  83. {
  84. dep[v]=dep[cr]+; d2[v]=d2[cr]+w[i];
  85. ini_dfs(v,cr);
  86. }
  87. }
  88. void init()
  89. {
  90. ll z;
  91. for(int i=,u,v;i<n;i++)
  92. u=rdn(),v=rdn(),z=rdn(),add(u,v,z);
  93. ini_dfs(,);
  94. }
  95. ll calc(int x,int y)
  96. {
  97. ll ret=d1[x]+d1[y]+d2[x]+d2[y]+d3[x]+d3[y];
  98. int tmp=T3::get_lca(x,y);
  99. ret-=(d3[tmp]<<1ll);
  100. return ret;
  101. }
  102. Node operator+ (const Node &a,const Node &b)
  103. {
  104. int x1=a.x,y1=a.y,x2=b.x,y2=b.y;
  105. Node ret=Node(,,-); ll tmp;
  106. if(x1&&x2)
  107. { tmp=calc(x1,x2); if(tmp>ret.w)ret=Node(x1,x2,tmp);}
  108. if(x1&&y2)
  109. { tmp=calc(x1,y2); if(tmp>ret.w)ret=Node(x1,y2,tmp);}
  110. if(y1&&x2)
  111. { tmp=calc(y1,x2); if(tmp>ret.w)ret=Node(y1,x2,tmp);}
  112. if(y1&&y2)
  113. { tmp=calc(y1,y2); if(tmp>ret.w)ret=Node(y1,y2,tmp);}
  114. return ret;
  115. }
  116. Node mx(Node a,Node b){ return a.w>b.w?a:b;}
  117. void link(int cr,int v,ll tw)
  118. {
  119. ll tmp=d2[cr]<<1ll;
  120. ans=Mx(ans,(dp[cr][]+dp[v][]).w+tw-tmp);
  121. ans=Mx(ans,(dp[cr][]+dp[v][]).w+tw-tmp);
  122. dp[cr][]=mx(dp[cr][],mx(dp[v][],dp[cr][]+dp[v][]));
  123. dp[cr][]=mx(dp[cr][],mx(dp[v][],dp[cr][]+dp[v][]));
  124. dp[v][]=dp[v][]=Node(,,-);
  125. }
  126. int solve(int l,int r,ll tw)
  127. {
  128. sta[top=]=a[l];
  129. for(int i=l+;i<=r;i++)
  130. {
  131. int lm=dep[lca[i]];
  132. while(top&&dep[sta[top]]>lm)
  133. {
  134. if(dep[sta[top-]]>lm)link(sta[top-],sta[top],tw);
  135. else link(lca[i],sta[top],tw);
  136. top--;
  137. }
  138. if(sta[top]!=lca[i])sta[++top]=lca[i];
  139. sta[++top]=a[i];
  140. }
  141. for(int i=top-;i;i--)link(sta[i],sta[i+],tw);
  142. dp[sta[]][]=dp[sta[]][]=Node(,,-);
  143. int mid=l-;
  144. for(int i=l,tl=;i<=r;i++)
  145. {
  146. if(!tl||dep[lca[i]]<dep[tl])tl=lca[i];
  147. if(!lx[a[i]]) ta[++mid]=a[i], tlca[mid]=tl, tl=;
  148. }
  149. int ret=mid;
  150. for(int i=l,tl=;i<=r;i++)
  151. {
  152. if(!tl||dep[lca[i]]<dep[tl])tl=lca[i];
  153. if(lx[a[i]]) ta[++mid]=a[i], tlca[mid]=tl, tl=;
  154. }
  155. for(int i=l;i<=r;i++)a[i]=ta[i];
  156. for(int i=l;i<=r;i++)lca[i]=tlca[i];
  157. return ret;
  158. }
  159. }
  160. void add(int x,int y,ll z)
  161. {
  162. to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;w[xnt]=z;
  163. to[++xnt]=x;nxt[xnt]=hd[y];hd[y]=xnt;w[xnt]=z;
  164. }
  165. void del_ed(int x,int y)
  166. {
  167. if(to[hd[x]]==y)hd[x]=nxt[hd[x]];
  168. else
  169. {
  170. for(int i=hd[x],pr;i;pr=i,i=nxt[i])
  171. if(to[i]==y){nxt[pr]=nxt[i];break;}
  172. }
  173. if(to[hd[y]]==x)hd[y]=nxt[hd[y]];
  174. else
  175. {
  176. for(int i=hd[y],pr;i;pr=i,i=nxt[i])
  177. if(to[i]==x){nxt[pr]=nxt[i];break;}
  178. }
  179. }
  180. void Rbuild(int cr,int fa)
  181. {
  182. for(int i=,lst=,lm=vt[cr].size();i<lm;i++)
  183. {
  184. int v=vt[cr][i].first;ll z=vt[cr][i].second;
  185. if(v==fa)continue;
  186. if(!lst)add(cr,v,z), lst=cr;
  187. else{ tn++; add(lst,tn,); add(tn,v,z); lst=tn;}
  188. }
  189. for(int i=,v,lm=vt[cr].size();i<lm;i++)
  190. if((v=vt[cr][i].first)!=fa) Rbuild(v,cr);
  191. }
  192. void get_rt(int cr,int fa,int s)
  193. {
  194. siz[cr]=;
  195. for(int i=hd[cr],v;i;i=nxt[i])
  196. if((v=to[i])!=fa)
  197. {
  198. get_rt(v,cr,s); siz[cr]+=siz[v];
  199. int mx=Mx(siz[v],s-siz[v]);
  200. if(mx<mn)mn=mx,Rt=i;
  201. }
  202. }
  203. void dfs(int cr,int fa,ll lj,bool fx)
  204. {
  205. d1[cr]=lj; lx[cr]=fx;
  206. T2::dp[cr][fx]=T2::Node(cr,cr,);
  207. T2::dp[cr][!fx]=T2::Node(,,-);
  208. for(int i=hd[cr],v;i;i=nxt[i])
  209. if((v=to[i])!=fa) dfs(v,cr,lj+w[i],fx);
  210. }
  211. void solve(int cr,int s,int l,int r)
  212. {
  213. int u=to[cr^], v=to[cr]; del_ed(u,v);
  214. dfs(u,,,); dfs(v,,,); ll tw=w[cr];
  215. int mid=T2::solve(l,r,tw);
  216. int ts=siz[v];
  217. if(ts>){mn=N;get_rt(v,,ts);solve(Rt,ts,mid+,r);}
  218. ts=s-ts;
  219. if(ts>){mn=N;get_rt(u,,ts);solve(Rt,ts,l,mid);}
  220. }
  221. int main()
  222. {
  223. n=rdn();ll z;
  224. for(int i=,u,v;i<n;i++)
  225. {
  226. u=rdn();v=rdn();z=rdn();
  227. vt[u].pb(mkp(v,z)); vt[v].pb(mkp(u,z));
  228. }
  229. T2::init(); T3::init(); tn=n; Rbuild(,);
  230. mn=N;get_rt(,,tn);solve(Rt,tn,,n);
  231. printf("%lld\n",ans);
  232. return ;
  233. }

LOJ 2339 「WC2018」通道——边分治+虚树的更多相关文章

  1. @loj - 2339@ 「WC2018」通道

    目录 @desription@ @solution@ @accepted code@ @details@ @desription@ 11328 年,C 国的科学家们研发了一种高速传送通道,可以在很短的 ...

  2. UOJ#347. 【WC2018】通道 边分治 虚树

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ347.html 题意 有三棵树,边有边权. 对于所有点对 (x,y) 求在三棵树上 x 到 y 的距离之和 ...

  3. 【UOJ347】【WC2018】通道 边分治 虚树 DP

    题目大意 给你三棵树,点数都是\(n\).求 \[ \max_{i,j}d_1(i,j)+d_2(i,j)+d_3(i,j) \] 其中\(d_k(i,j)\)是在第\(k\)棵数中\(i,j\)两点 ...

  4. 「WC2018」通道

    没有代码能力... LOJ #2339 Luogu P4220 UOJ #347 题意 给定三棵树$ T1,T2,T3$,求一个点对$ (x,y)$使得$ T1.dist(x,y)+T2.dist(x ...

  5. [WC2018]通道——边分治+虚树+树形DP

    题目链接: [WC2018]通道 题目大意:给出三棵n个节点结构不同的树,边有边权,要求找出一个点对(a,b)使三棵树上这两点的路径权值和最大,一条路径权值为路径上所有边的边权和. 我们按照部分分逐个 ...

  6. loj#2312. 「HAOI2017」八纵八横(线性基 线段树分治)

    题意 题目链接 Sol 线性基+线段树分治板子题.. 调起来有点自闭.. #include<bits/stdc++.h> #define fi first #define se secon ...

  7. loj#2340. 「WC2018」州区划分

    FWT&&FMT板子 #include<cstdio> #include<iostream> #include<cstring> #include& ...

  8. LOJ 3055 「HNOI2019」JOJO—— kmp自动机+主席树

    题目:https://loj.ac/problem/3055 先写了暴力.本来想的是 n<=300 的那个在树上暴力维护好整个字符串, x=1 的那个用主席树维护好字符串和 nxt 数组.但 x ...

  9. LOJ 2302 「NOI2017」整数——压位线段树

    题目:https://loj.ac/problem/2302 压30位,a最多落在两个位置上,拆成两次操作. 该位置加了 a 之后,如果要进位或者借位,查询一下连续一段 0 / 1 ,修改掉,再在含有 ...

随机推荐

  1. day55 jQuery 练习

    <!DOCTYPE html><html lang="zh-CN"><head> <meta charset="UTF-8&qu ...

  2. 爬虫框架存储pymysql方式

    爬虫框架存储pymysql方式# -*- coding: utf-8 -*-import pymysql# Define your item pipelines here## Don't forget ...

  3. scrapy shell的作用

    1.可以方便我们做一些数据提取的测试代码: 2.如果想要执行scrapy命令,那么毫无疑问,肯定是要先进入到scrapy所在的环境中: 3.如果想要读取某个项目的配置信息,那么应该先进入到这个项目中. ...

  4. POJ 2234 Matches Game(Nim博弈裸题)

    Description Here is a simple game. In this game, there are several piles of matches and two players. ...

  5. 【转载】 pytorch自定义网络结构不进行参数初始化会怎样?

    原文地址: https://blog.csdn.net/u011668104/article/details/81670544 ------------------------------------ ...

  6. Smali插桩打日志

    一.smali目录下新建crack.smali,内容如下: .class public Lcrack; .super Ljava/lang/Object; .source "crack.ja ...

  7. Django之静态文件配置

    在项目目录中打开settings.py,在最下面配置静态文件(css文件,js文件以及其他静态配置文件),比如说html使用到了jQuery框架,我们要在项目根目录下创建statics(可自定义),将 ...

  8. jQuery对标签、类样式、值、文档、DOM对象的操作

    jquery的标签属性操作 使用attr()方法对html标签属性进行操作,attr如果参数是一个参数,表示获取html标签的属性值,如果是两个参数则是设置标签属性名以及对象的属性值 .prop()适 ...

  9. Samsung_tiny4412(驱动笔记04)----volatile,container_of,file_operations,file,inode

    /*********************************************************************************** * * volatile,co ...

  10. JAXB性能优化

    前言: 之前在查阅jaxb相关资料的同时, 也看到了一些关于性能优化的点. 主要集中于对象和xml互转的过程中, 确实有些实实在在需要注意的点. 这边浅谈jaxb性能优化的一个思路. 案列: 先来构造 ...