没有代码能力...

LOJ #2339

Luogu P4220

UOJ #347


题意

给定三棵树$ T1,T2,T3$,求一个点对$ (x,y)$使得$ T1.dist(x,y)+T2.dist(x,y)+T3.dist(x,y)$最大

每棵树的点数为$ 10^5$,时限$ 4s$


$ Solution$

尝试对$ T1$边分治

设当前分治到边$(L,R)$

将$ L$及$ L$所在一侧的点染黑,将$ R$及$ R$所在一侧的点染白

问题转化为找到一个点对$ (x,y)$使得满足$ x$为黑点$ y$为白点

并且最大化

$ T1.dist(x,L)+T1.dist(y,R)+len(x,y)+T2.dist(x,y)+T3.dist(x,y)$

考虑将所有黑白点拿出来在$ T2$上构一棵虚树

在虚树上$ DP$

有一些不那么显然的性质:

设两端均为黑色的最长路径的两个端点为$ (B1,B2)$,两端均为白色的最长路径的两个端点为$ (W1,W2)$

则两端异色的最长路径的两个端点一定在$ B1,B2,W1,W2$中出现过

设点集$ S$的黑色最长路径的两个端点为$ (B1,B2)$,点集$ T$的黑色最长路径的两个端点为$ (B3,B4)$

则点集$ S \cup T$的黑色最长路径的两个端点一定在$ B1,B2,B3,B4$中出现过

用这两个性质就可以在虚树上$ DP$了

形象化地,设我们在虚树上枚举点对在$ T2$上的$ LCA$

则这个点对一定来自于枚举的$ LCA$的不同子树

在每个子树记录黑色/白色最长路径的端点然后合并转移即可

时间复杂度$ O(n \ log^2 \ n)$


$my \ code$

  1. #include<ctime>
  2. #include<cmath>
  3. #include<cstdio>
  4. #include<cstring>
  5. #include<iostream>
  6. #include<algorithm>
  7. #include<queue>
  8. #include<vector>
  9. #define M 500010
  10. #define rt register int
  11. #define ll long long
  12. using namespace std;
  13. namespace fast_IO{
  14. const int IN_LEN=,OUT_LEN=;
  15. char ibuf[IN_LEN],*ih=ibuf+IN_LEN,*lastin=ibuf+IN_LEN;
  16. inline char getchar_(){return (ih==lastin)&&(lastin=(ih=ibuf)+fread(ibuf,,IN_LEN,stdin),ih==lastin)?EOF:*ih++;}
  17. }
  18. using namespace fast_IO;
  19. #define getchar() getchar_()
  20. inline ll read(){
  21. ll x=;char zf=;char ch=getchar();
  22. while(ch!='-'&&!isdigit(ch))ch=getchar();
  23. if(ch=='-')zf=-,ch=getchar();
  24. while(isdigit(ch))x=x*+ch-'',ch=getchar();return x*zf;
  25. }
  26. void write(ll y){if(y<)putchar('-'),y=-y;if(y>)write(y/);putchar(y%+);}
  27. void writeln(const ll y){write(y);putchar('\n');}
  28. int k,m,n,x,y,z,cnt,B,W,la;ll ans;
  29. int sorttable[M];ll dist[M];
  30. bool cmp(int x,int y){return sorttable[x]<sorttable[y];}
  31. int sz[M],A[M],col[M];bool vis[M];
  32. int nowmin,all,ed,sum,Root;
  33. struct node{int a;ll c;};
  34. vector<node>e[M];
  35. struct tree{
  36. int F[M],L[M],N[M],a[M],dfn[M],q[M],size[M],k=,t=,cnt=;ll deep[M],c[M];
  37. int st[][M],fa[M],lg2[M],fir[M],dep[M];
  38. void clear(){
  39. for(rt i=;i<=k;i++)F[a[i]]=,N[i]=;
  40. F[Root]=;k=;t=;cnt=;
  41. }
  42. void add(int x,int y,ll z){
  43. a[++k]=y;c[k]=z;
  44. if(!F[x])F[x]=k;
  45. else N[L[x]]=k;
  46. L[x]=k;
  47. }
  48. void dfs(int x,int pre){
  49. q[++t]=x;dfn[x]=++cnt;size[x]=;fa[x]=pre;fir[x]=t;
  50. for(rt i=F[x];i;i=N[i])if(a[i]!=pre){
  51. deep[a[i]]=deep[x]+c[i];
  52. dep[a[i]]=dep[x]+;
  53. dfs(a[i],x);
  54. size[x]+=size[a[i]];
  55. q[++t]=x;
  56. }
  57. }
  58.  
  59. void rebuild_init(int x,int pre){
  60. for(rt i=F[x];i;i=N[i])if(a[i]!=pre){
  61. e[x].push_back({a[i],c[i]});
  62. rebuild_init(a[i],x);
  63. }
  64. }
  65. void rebuild(){
  66. clear();
  67. for(rt i=;i<=n;i++){
  68. if(e[i].size()<=)for(auto j:e[i])add(i,j.a,j.c*(j.a<=la)),add(j.a,i,j.c*(j.a<=la));
  69. else {
  70. int v1=++n,v2=++n;
  71. add(i,v1,);add(v1,i,);add(i,v2,);add(v2,i,);
  72. for(rt j=;j<e[i].size();j++)if(j&)e[v1].push_back(e[i][j]);
  73. else e[v2].push_back(e[i][j]);
  74. }
  75. }
  76.  
  77. }
  78. int mins(int x,int y){return dep[x]<dep[y]?x:y; }
  79. void LCA_init(){
  80. for(rt i=;i<=t;i++)st[][i]=q[i];
  81. for(rt i=;i<=;i++)
  82. for(rt j=;j<=t;j++)
  83. st[i][j]=mins(st[i-][j],st[i-][min(t,j+(<<i-))]);
  84. for(rt i=;i<=t;i++)lg2[i]=lg2[i>>]+;
  85. }
  86. inline int LCA(const int x,const int y){
  87. int L=fir[x],R=fir[y];if(L>R)swap(L,R);
  88. const int len=lg2[R-L+];
  89. return mins(st[len][L],st[len][R-(<<len)+]);
  90. }
  91. inline ll dis(const int x,const int y){
  92. return deep[x]+deep[y]-deep[LCA(x,y)]*;
  93. }
  94. inline bool anc(const int x,const int y){//x是否为y祖先
  95. return dfn[x]<=dfn[y]&&dfn[x]+size[x]->=dfn[y];
  96. }
  97. }T1,T2,T3,xs;
  98. void build(int n,int *A){
  99. xs.clear();//对于点集A在xs上建虚树
  100. static int q[M],sta[M];int tott=n,topp=;
  101. static bool vis[M];
  102. for(rt i=;i<=n;i++)q[i]=A[i],vis[q[i]]=;
  103. for(rt i=;i<=n;i++)sorttable[i]=T2.dfn[q[i]];
  104. sort(q+,q+n+,cmp);
  105. for(rt i=n;i>=;i--){
  106. int lca=T2.LCA(q[i],q[i-]);
  107. if(!vis[lca])vis[lca]=,q[++tott]=lca,col[lca]=;
  108. }
  109. for(rt i=;i<=tott;i++)sorttable[q[i]]=T2.dfn[q[i]];
  110. sort(q+,q+tott+,cmp);
  111. sta[topp=]=q[];
  112. for(rt i=;i<=tott;i++){
  113. while(topp&&!T2.anc(sta[topp],q[i]))topp--;
  114. if(topp){
  115. ll val=-T2.deep[sta[topp]]+T2.deep[q[i]];
  116. xs.add(sta[topp],q[i],val);
  117. }sta[++topp]=q[i];
  118. }
  119. for(rt i=;i<=tott;i++)vis[q[i]]=;
  120. Root=q[];
  121. }
  122.  
  123. void printblack(int x,int pre,ll ds=){//黑1白2
  124. if(x<=la)A[++sum]=x,col[x]=,dist[x]=ds;
  125. for(rt i=T1.F[x];i;i=T1.N[i])if(T1.a[i]!=pre&&!vis[i>>])printblack(T1.a[i],x,ds+T1.c[i]);
  126. }
  127. void printwhite(int x,int pre,ll ds=){//黑1白2
  128. if(x<=la)A[++sum]=x,col[x]=,dist[x]=ds;
  129. for(rt i=T1.F[x];i;i=T1.N[i])if(T1.a[i]!=pre&&!vis[i>>])printwhite(T1.a[i],x,ds+T1.c[i]);
  130. }
  131. void get(int x,int pre){
  132. sz[x]=;
  133. for(rt i=T1.F[x];i;i=T1.N[i])if(T1.a[i]!=pre&&!vis[i>>]){
  134. get(T1.a[i],x);
  135. const int val=abs(all-*sz[T1.a[i]]);
  136. if(val<nowmin)nowmin=val,ed=i;
  137. sz[x]+=sz[T1.a[i]];
  138. }
  139. }
  140. ll calc(int x,int y){//左黑右白
  141. if(x==-||y==-)return -100000000000000ll;
  142. return dist[x]+dist[y]+T2.deep[x]+T2.deep[y]+T3.dis(x,y);
  143. }
  144. struct white{int x,y;};
  145. struct black{int x,y;};
  146. ll calcw(white x){
  147. return dist[x.x]+dist[x.y]+T2.deep[x.x]+T2.deep[x.y]+T3.dis(x.x,x.y);
  148. }
  149. ll calcb(black x){
  150. return dist[x.x]+dist[x.y]+T2.deep[x.x]+T2.deep[x.y]+T3.dis(x.x,x.y);
  151. }
  152. white maxw(white x,white y){
  153. if(x.x==-&&x.y==-)return y;
  154. if(y.x==-&&y.y==-)return x;
  155. if(x.x==-||x.y==-)return y;
  156. if(y.x==-||y.y==-)return x;
  157. if(calcw(x)>calcw(y))return x;else return y;
  158. }
  159. black maxb(black x,black y){
  160. if(x.x==-&&x.y==-)return y;
  161. if(y.x==-&&y.y==-)return x;
  162. if(x.x==-||x.y==-)return y;
  163. if(y.x==-||y.y==-)return x;
  164. if(calcb(x)>calcb(y))return x;else return y;
  165. }
  166. inline white operator +(const white x,const white y){
  167. return maxw(maxw(x,y),maxw(maxw(maxw((white){x.x,y.x},(white){x.x,y.y}),(white){x.y,y.x}),(white){x.y,y.y}));
  168. }
  169. inline black operator +(const black x,const black y){
  170. return maxb(maxb(x,y),maxb(maxb(maxb((black){x.x,y.x},(black){x.x,y.y}),(black){x.y,y.x}),(black){x.y,y.y}));
  171. }
  172. inline ll Calc(const black x,const white y){
  173. return max(max(max(calc(x.x,y.x),calc(x.x,y.y)),calc(x.y,y.x)),calc(x.y,y.y));
  174. }
  175. pair<black,white>DP(int x,ll val){
  176. pair<black,white>ret={{-,-},{-,-}};
  177. if(col[x]==)ret.first.x=x;
  178. if(col[x]==)ret.second.x=x;
  179. for(rt i=xs.F[x];i;i=xs.N[i]){
  180. pair<black,white>la=DP(xs.a[i],val);
  181. ll res=max(Calc(ret.first,la.second),Calc(la.first,ret.second))+val-2ll*T2.deep[x];
  182. ans=max(ans,res);
  183. ret.first=ret.first+la.first;
  184. ret.second=ret.second+la.second;
  185. }
  186. return ret;
  187. }
  188. void solve(int x,int siz){
  189. if(siz==)return;
  190. nowmin=all=siz;
  191. get(x,x);
  192. int xx=T1.a[ed],yy=T1.a[ed^];vis[ed>>]=;int now=sz[xx];
  193. sum=;printblack(xx,yy);printwhite(yy,xx);B=xx;W=yy;
  194. build(sum,A);DP(Root,T1.c[ed]);
  195. solve(xx,now);solve(yy,siz-now);
  196. }
  197. int main(){
  198. n=read();la=n;
  199. for(rt i=;i<n;i++){
  200. x=read();y=read();ll z=read();
  201. T1.add(x,y,z);
  202. T1.add(y,x,z);
  203. }
  204. for(rt i=;i<n;i++){
  205. x=read();y=read();ll z=read();
  206. T2.add(x,y,z);
  207. T2.add(y,x,z);
  208. }
  209. for(rt i=;i<n;i++){
  210. x=read();y=read();ll z=read();
  211. T3.add(x,y,z);
  212. T3.add(y,x,z);
  213. }
  214. T1.rebuild_init(,);T1.rebuild();
  215. T1.dfs(,);T1.LCA_init();T2.dfs(,);T2.LCA_init();T3.dfs(,);T3.LCA_init();
  216. solve(,n);
  217. cout<<ans;
  218. return ;
  219. }

「WC2018」通道的更多相关文章

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

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

  2. LOJ 2339 「WC2018」通道——边分治+虚树

    题目:https://loj.ac/problem/2339 两棵树的话,可以用 CTSC2018 暴力写挂的方法,边分治+虚树.O(nlogn). 考虑怎么在这个方法上再加一棵树.发现很难弄. 看了 ...

  3. 「WC2018」州区划分(FWT)

    「WC2018」州区划分(FWT) 我去弄了一个升级版的博客主题,比以前好看多了.感谢 @Wider 不过我有阅读模式的话不知为何 \(\text{LATEX}\) 不能用,所以我就把这个功能删掉了. ...

  4. 「WC2018」即时战略

    「WC2018」即时战略 考虑对于一条链:直接随便找点,然后不断问即可. 对于一个二叉树,树高logn,直接随便找点,然后不断问即可. 正解: 先随便找到一个点,问出到1的路径 然后找别的点,考虑问出 ...

  5. loj2341「WC2018」即时战略(随机化,LCT/动态点分治)

    loj2341「WC2018」即时战略(随机化,LCT/动态点分治) loj Luogu 题解时间 对于 $ datatype = 3 $ 的数据,explore操作次数只有 $ n+log n $ ...

  6. 【LOJ】#2340. 「WC2018」州区划分

    题解 学习一个全世界人都会只有我不会的东西 子集变换! 难道我要把这题当板子讲?等等这题好像是板...WC出板题好刺激啊= = 假装我们都做过HAOI2015的FMT题,我们都知道一些FMT怎么解决或 ...

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

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

  8. LOJ2341. 「WC2018」即时战略 [动态点分治]

    LOJ 思路 考虑最蠢的暴力:枚举2~n,从1拉一条到他们的链,需要查询\(n^2\)次,显然不能通过. 考虑优化:如果拉的第一个点已经被访问过了,那么类似二分的做法,一次往那个方向多跳几步. 多跳几 ...

  9. 「WC2018即时战略」

    「WC2018即时战略」 题目描述 小 M 在玩一个即时战略 (Real Time Strategy) 游戏.不同于大多数同类游戏,这个游戏的地图是树形的.也就是说,地图可以用一个由 \(n\) 个结 ...

随机推荐

  1. Jenkins pipeline:pipeline 使用之语法详解

    一.引言 Jenkins 2.0的到来,pipline进入了视野,jenkins2.0的核心特性. 也是最适合持续交付的feature. 简单的来说,就是把Jenkins1.0版本中,Project中 ...

  2. 【vue】vue全家桶

    vue-router(http://router.vuejs.org) vuex(https://vuex.vuejs.org/zh/guide/) vue-resource(https://gith ...

  3. 在C#/.NET应用程序开发中创建一个基于Topshelf的应用程序守护进程(服务)

    本文首发于:码友网--一个专注.NET/.NET Core开发的编程爱好者社区. 文章目录 C#/.NET基于Topshelf创建Windows服务的系列文章目录: C#/.NET基于Topshelf ...

  4. 《通过C#学Proto.Actor模型》之Persistence

    Actor是有状态的,当每一步执行失败后,返回失败地方继续执行时,希望此时的状态是正确的,为了保证这一点,持久化就成了必要的环节了. Proto.Actor提供了三种方式执久化: Event Sour ...

  5. 第十一节,利用yolov3训练自己的数据集

    1.环境配置 tensorflow1.12.0 Opencv3.4.2 keras pycharm 2.配置yolov3 下载yolov3代码:https://github.com/qqwweee/k ...

  6. iOS开发基础篇-transform属性

    一. transform 属性 在OC中,通过 transform 属性可以修改对象的平移.缩放比例和旋转角度. 1)创建“基于控件初始位置”的形变  CGAffineTransformMakeRot ...

  7. Laravel 和 Spring Boot 两个框架比较创业篇(一:开发效率)

    我个人是比较不喜欢去正儿八经的比较两个框架的,这样没有意义,不过欲善其事先利其器! 技术是相通的,但是在某个特定的领域的某个阶段肯定有相对最适合的一个工具! 这里比较不是从技术角度比较,而是从公司技术 ...

  8. 迄今为止 .Net 平台功能最强大,性能最佳的 JSON 序列化和反序列化库。

    Swifter.Json 这是迄今为止 .Net 平台功能最强大,性能最佳的 JSON 序列化和反序列化库. Github : https://github.com/Dogwei/Swifter.Js ...

  9. docker 搭建 Telegram Messenger MTP

    docker hub官方镜像地址如下: https://hub.docker.com/r/telegrammessenger/proxy 拉取镜像 sudo docker pull telegramm ...

  10. html2canvas截屏在H5微信移动端踩坑,ios和安卓均可显示

    1.最近在做移动端开发,框架是vue,一产品需求是,后台返回数据,通过qrcode.js(代码比较简单,百度上已经很多了)生成二维码,然后通过html2canvas,将html元素转化为canvas, ...