【WC2018】通道【边分治】【虚树】【树的直径】
题意:给三棵基于同一点集的带边权的树,边权非负,求两点间三棵树上距离之和的最大值。
n≤105n\leq 10^5n≤105
一句话题解:在第一棵树上做边分治,丢到第二棵树上建虚树,在虚树上根据第三棵树的直径dp。
首先,这个问题难搞的地方只在于需要统计 lca。所以我们做的一切工作都是为了搞掉 lca 。
在求最大值的问题上有以下搞法:
- 树分治
- 枚举 lca 统计贡献。或者说就是 dp。
把这两个合起来就可以做 暴力写挂 了。但这个问题还多了一棵树,还要再用一个方法。
哲学分析,如果没有特殊性质,剩下这个方法肯定不会太弱于点分治,然后你就可以弃疗了。仔细观察,这题唯一有的特殊条件就只有藏在数据范围里的边权非负了。
边权非负的时候直径是可以合并的,所以第三个方法就是利用直径。
整理一下,在第一棵树上点分治,通过到分治中心的距离之和代替距离,搞掉第一棵树的 lca。在第二棵树的虚树上 dp,只在 lca 处更新答案,搞掉第二棵树的 lca。在 dp 时记录虚树的子树中两种颜色的点集在第三棵树上的直径,枚举端点合并,直接处理第三棵树上的距离。
设分治中心边的边权为 www,第一棵树上的点到分治中心的距离为 disdisdis,第二棵树上的点的深度为 depdepdep,第三棵树上两点距离为 distdistdist,我们相当于求这个东西的最大值
w+disa+disb+depa+depb−2deplca(a,b)+dist(a,b)w+dis_a+dis_b+dep_a+dep_b-2dep_{\operatorname{lca}(a,b)}+dist(a,b)w+disa+disb+depa+depb−2deplca(a,b)+dist(a,b)
我们假装在第三棵树上每个点挂两个叶子,边权为 disa+depadis_a+dep_adisa+depa,所以直径可合并的结论在端点有权值时也是成立的。
复杂度是 O(nlogn)O(n\log n)O(nlogn)。
人生最长代码,不过很多复制粘贴,不算难写。
要注意虚树上的虚点不属于任何颜色。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <vector>
#include <algorithm>
#define MAXN 200005
#define MAXM 400005
using namespace std;
typedef long long ll;
const int INF=0x7fffffff;
inline int read()
{int ans=0;char c=getchar();while (!isdigit(c)) c=getchar();while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();return ans;
}
inline ll readll()
{ll ans=0;char c=getchar();while (!isdigit(c)) c=getchar();while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();return ans;
}
struct edge{int u,v;ll w;}e[MAXM];
int head[MAXN],nxt[MAXM],cnt=1;
inline void addnode(int u,int v,ll w)
{e[++cnt]=(edge){u,v,w};nxt[cnt]=head[u];head[u]=cnt;
}
vector<edge> E[MAXN];
int vis[MAXN],n,tot;
void dfs(int u)
{vis[u]=1;if ((int)E[u].size()<=3){for (int i=0;i<(int)E[u].size();i++){int v=E[u][i].v;ll w=E[u][i].w;if (!vis[v])dfs(v),addnode(u,v,w),addnode(v,u,w); }return;}int cur[2]={++tot,++tot},pos=0;addnode(u,cur[0],0),addnode(cur[0],u,0);addnode(u,cur[1],0),addnode(cur[1],u,0);for (int i=0;i<(int)E[u].size();i++)if (!vis[E[u][i].v])E[cur[pos^=1]].push_back(E[u][i]);dfs(cur[0]),dfs(cur[1]);
}
int rt,mi,siz[MAXN];
void findrt(int u,int f,int sum)
{siz[u]=1;for (int i=head[u];i;i=nxt[i])if (!vis[i>>1]&&e[i].v!=f){findrt(e[i].v,u,sum);if (max(siz[e[i].v],sum-siz[e[i].v])<mi) mi=max(siz[e[i].v],sum-siz[e[i].v]),rt=i;siz[u]+=siz[e[i].v];}
}
int LOG[MAXM];
namespace FT
{edge e[MAXM];int head[MAXN],nxt[MAXM],cnt;inline void addnode(int u,int v,ll w){e[++cnt]=(edge){u,v,w};nxt[cnt]=head[u];head[u]=cnt;}ll dis[MAXN],val[MAXN];int dfn[MAXN],lis[MAXM],tim;inline bool cmp(const int& x,const int& y){return dfn[x]<dfn[y];}void dfs(int u,int f){lis[dfn[u]=++tim]=u;for (int i=head[u];i;i=nxt[i])if (e[i].v!=f){dis[e[i].v]=dis[u]+e[i].w;dfs(e[i].v,u);lis[++tim]=u;}}int st[MAXM][20];inline int lca(int x,int y){x=dfn[x],y=dfn[y];if (x>y) swap(x,y);int t=LOG[y-x+1];return min(st[x][t],st[y-(1<<t)+1][t],cmp);}inline ll dist(int x,int y){return x&&y? dis[x]+dis[y]+val[x]+val[y]-2*dis[lca(x,y)]:-1;}void input(){for (int i=1;i<n;i++){int u,v;ll w;u=read(),v=read(),w=readll();addnode(u,v,w),addnode(v,u,w);}dfs(1,0);for (int i=1;i<=tim;i++) st[i][0]=lis[i];for (int j=1;j<20;j++)for (int i=1;i+(1<<(j-1))<=tim;i++)st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1],cmp);}
}
namespace VT
{edge e[MAXM];int head[MAXN],nxt[MAXM],cnt;inline void addnode(int u,int v,ll w){e[++cnt]=(edge){u,v,w};nxt[cnt]=head[u];head[u]=cnt;}ll dis[MAXN];int dfn[MAXN],lis[MAXM],tim;inline bool cmp(const int& x,const int& y){return dfn[x]<dfn[y];}void dfs(int u,int f){lis[dfn[u]=++tim]=u;for (int i=head[u];i;i=nxt[i])if (e[i].v!=f){dis[e[i].v]=dis[u]+e[i].w;dfs(e[i].v,u);lis[++tim]=u;}}int st[MAXM][20],col[MAXN];inline int lca(int x,int y){x=dfn[x],y=dfn[y];if (x>y) swap(x,y);int t=LOG[y-x+1];return min(st[x][t],st[y-(1<<t)+1][t],cmp);}void input(){memset(col,-1,sizeof(col));for (int i=1;i<n;i++){int u,v;ll w;u=read(),v=read(),w=readll();addnode(u,v,w),addnode(v,u,w);}dfs(1,0);for (int i=1;i<=tim;i++) st[i][0]=lis[i];for (int j=1;j<20;j++)for (int i=1;i+(1<<(j-1))<=tim;i++)st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1],cmp);}vector<int> p,son[MAXN];struct path{int x,y;inline path(const int& x=0,const int& y=0):x(x),y(y){}};inline ll calc(const path& a){return FT::dist(a.x,a.y);}inline bool operator <(const path& a,const path& b){return calc(a)<calc(b);}int stk[MAXN],tp;path mx[MAXN][2];ll ans;void dfs(int u){mx[u][0]=mx[u][1]=path(0,0);if (~col[u]) mx[u][col[u]]=path(u,u);for (int i=0;i<(int)son[u].size();i++){int v=son[u][i];dfs(v);path t;t=max(t,path(mx[u][0].x,mx[v][1].x));t=max(t,path(mx[u][0].x,mx[v][1].y));t=max(t,path(mx[u][0].y,mx[v][1].x));t=max(t,path(mx[u][0].y,mx[v][1].y));t=max(t,path(mx[u][1].x,mx[v][0].x));t=max(t,path(mx[u][1].x,mx[v][0].y));t=max(t,path(mx[u][1].y,mx[v][0].x));t=max(t,path(mx[u][1].y,mx[v][0].y));ans=max(ans,calc(t)-2*dis[u]);t=max(mx[u][0],mx[v][0]);t=max(t,path(mx[u][0].x,mx[v][0].x));t=max(t,path(mx[u][0].x,mx[v][0].y));t=max(t,path(mx[u][0].y,mx[v][0].x));t=max(t,path(mx[u][0].y,mx[v][0].y));mx[u][0]=t;t=max(mx[u][1],mx[v][1]);t=max(t,path(mx[u][1].x,mx[v][1].x));t=max(t,path(mx[u][1].x,mx[v][1].y));t=max(t,path(mx[u][1].y,mx[v][1].x));t=max(t,path(mx[u][1].y,mx[v][1].y));mx[u][1]=t;}}ll solve(){sort(p.begin(),p.end(),cmp);int s=p.size();for (int i=0;i<s-1;i++) p.push_back(lca(p[i],p[i+1]));sort(p.begin(),p.end(),cmp);p.erase(unique(p.begin(),p.end()),p.end());tp=0;for (int i=0;i<(int)p.size();i++){while (tp&&lca(stk[tp],p[i])!=stk[tp]) --tp;if (tp) son[stk[tp]].push_back(p[i]);stk[++tp]=p[i];}ans=0;dfs(stk[1]);for (int i=0;i<(int)p.size();i++) son[p[i]].clear(),col[p[i]]=-1;p.clear();return ans;}
}
void dfs(int u,int f,int c,ll d)
{if (u<=n) FT::val[u]=d+VT::dis[u],VT::p.push_back(u),VT::col[u]=c;for (int i=head[u];i;i=nxt[i])if (!vis[i>>1]&&e[i].v!=f)dfs(e[i].v,u,c,d+e[i].w);
}
ll ans;
void solve(int sum)
{if (mi==INF) return;vis[rt>>1]=1;dfs(e[rt].v,0,0,0);dfs(e[rt].u,0,1,0); ans=max(ans,VT::solve()+e[rt].w);int cur=rt,sz=siz[e[rt].v];mi=INF,findrt(e[cur].v,0,sz),solve(sz);mi=INF,findrt(e[cur].u,0,sum-sz),solve(sum-sz);
}
int main()
{LOG[0]=-1;for (int i=1;i<MAXM;i++) LOG[i]=LOG[i>>1]+1;tot=n=read();for (int i=1;i<n;i++){int u,v;ll w;u=read(),v=read(),w=readll();E[u].push_back((edge){u,v,w}),E[v].push_back((edge){v,u,w});}dfs(1);memset(vis,0,sizeof(vis));VT::input();FT::input();mi=INF,findrt(1,0,tot),solve(tot);cout<<ans;return 0;
}
【WC2018】通道【边分治】【虚树】【树的直径】相关推荐
- [WC2018]通道——边分治+虚树+树形DP
题目链接: [WC2018]通道 题目大意:给出三棵n个节点结构不同的树,边有边权,要求找出一个点对(a,b)使三棵树上这两点的路径权值和最大,一条路径权值为路径上所有边的边权和. 我们按照部分分逐个 ...
- LOJ 2339 「WC2018」通道——边分治+虚树
题目:https://loj.ac/problem/2339 两棵树的话,可以用 CTSC2018 暴力写挂的方法,边分治+虚树.O(nlogn). 考虑怎么在这个方法上再加一棵树.发现很难弄. 看了 ...
- 虚树+树型DP SDOI2011消耗战
<虚树+树型DP> SDOI2011消耗战 #include <iostream> #include <cstdio> #include <cstring&g ...
- 【2016北京集训测试赛(八)】 直径 (虚树+树的直径)
Description 注意:时限更改为4s 题解 考虑最原始的直径求法:找到离根节点(或离其他任意一点)最远的节点far1,再从far1出发找到离far1最远的节点far2,far1至far2的距离 ...
- 2021牛客多校6K Starch Cat(点分治+猫树)
大意就是给一个树,给很多个问询,选择两个点之间的若干个点,在保证选择一个点后与其直接相连的点不能选,每次询问求总和最大值.必须在线. 最开始想的是树剖,但是做完签到后一看K题只有几个AC就果断run了 ...
- 主题图片_临床医学院“树树皆秋色,山山唯落晖”主题图片征集活动
自古逢秋悲寂寥,我言秋日胜春朝.秋风起,金叶舞,趵突泉校区迎来了金色的秋天.在老舍先生笔下,冬天是济南最美的季节,而在同学们的眼中,趵突泉校区的秋色更是别具一番风味.临床医学院新媒体中心特此举办&qu ...
- The Trip On Abandoned Railway(线段树+树状数组)
链接:https://ac.nowcoder.com/acm/problem/13891 来源:牛客网 题目描述 There are many ghosts at the abandoned stat ...
- [XSY] 智慧树(线性同余方程组,线段树/树状数组)
智慧树 解决此题有两个要点: 如何判断一个线性同余方程组有没有解 如何统计合法子序列数目 先看第2点: 若一个序列是合法的,则这个序列的所有子序列都是合法的 考虑对∀1≤i≤n\forall 1\le ...
- [Bzoj2243][SDOI2011]染色(线段树树剖)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2243 线段树+树链剖分,在线段树需要每次用lt和rt两个数组记录当前区间的左右边界的颜色 ...
- 408数据结构学习笔记-树-①树的逻辑结构
目录 ①定义 ②结点间的关系描述 ③结点路径 ④结点,树的属性描述 ⑤有序树和无序树 ⑥森林 ⑦树的性质(6个性质) a.结点数=总度数+1 b.度为m的树和m叉树的区别 c.度为m的树第i层至多有 ...
最新文章
- FSD键盘钩子框架参考爱写驱动的女装大佬
- java new thread参数_java线程池01-ThreadPoolExecutor构造方法参数的使用规则
- 2012-04-26 16:08 Director installer fails with error Unable to run run-cds-tool script“
- OData metadata 定义中,entity type key 的作用是什么
- SOL注入——HTTP头部注入(六)
- [转载]Informix Dynamic Server维护手册
- Atmel megaAVR控制器 串行引导Bootloader
- 树莓派基金会来号召用键盘生物学家研究企鹅
- 数据结构|-二叉查找树(二叉搜索树)的链式存储结构的实现
- windows下使用vim
- CurrentUser获取不到当前登录用户name
- 华为交换机开启ftp服务,上传和下载文件,get和put操作实例
- vivado2021.2安装及验证教程(绝大部分适用于同软件其他版本)
- Axure手机原型图总结
- 第十届山东理工大学ACM网络编程擂台赛 重现
- 运算放大器---封装尺寸
- IBM推出企业信息安全框架
- 聚类算法K-Means
- java 从set取值_怎样从java集合类set中取出数据?
- Speedoffice(Word)怎样设置页眉页脚高度
热门文章
- 这个偏僻的小山村竟出了12位博士28位硕士,高产“学霸”背后原因曝光......
- 看OpenCV如何在python中实现图像检测!
- 原来R语言还有这些不为人知的用处!
- 分析函数在数据分析中的应用
- java launcher 下载_Java Launcher下载并安装
- java 线程 插件_我的第一个Chrome插件:天气预报应用
- mysql innodb表损坏_MySQL数据库INNODB表损坏修复处理过程分享
- 世道变了,面试初级Java开发会问到Arrays!!!你不会还不知道吧!
- 超详细图解!【MySQL进阶篇】存储过程,视图,索引,函数,触发器
- php return 变量,php内核笔记–函数返回变量return_value