【WC2018】通道【边分治】【虚树】【树的直径】

题意:给三棵基于同一点集的带边权的树,边权非负,求两点间三棵树上距离之和的最大值。

n≤105n\leq 10^5n105

一句话题解:在第一棵树上做边分治,丢到第二棵树上建虚树,在虚树上根据第三棵树的直径dp。

首先,这个问题难搞的地方只在于需要统计 lca。所以我们做的一切工作都是为了搞掉 lca 。

在求最大值的问题上有以下搞法:

  1. 树分治
  2. 枚举 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+depb2deplca(a,b)+dist(a,b)

我们假装在第三棵树上每个点挂两个叶子,边权为 disa+depadis_a+dep_adisa+depa,所以直径可合并的结论在端点有权值时也是成立的。

复杂度是 O(nlog⁡n)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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/314828.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DevOps案例研究:知人善任——Google敏捷核心文化

内容来源&#xff1a;DevOps案例深度研究-Google敏捷实践战队&#xff0c;本文只展示部分PPT及研究成果&#xff0c;更多细节请关注案例分享会。本文内容贡献者&#xff1a;陈霁、刘翀、谈佳婧、张霖。阅读干货前先感受一下热烈的氛围~一、Google如何快速交付原型1.1 Savioke公…

Educational Codeforces Round 111 (Rated for Div. 2) E. Stringforces 二分 + 状压dp

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你一个串&#xff0c;只包含前kkk个字母和&#xff1f;&#xff1f;&#xff1f;&#xff0c;定义fif_ifi​表示第iii个字母在串中出现的最长连续长度&#xff0c;你现在需要将???替换为前kkk个字母&am…

MTT 学习笔记

很久以前就听说了这东西&#xff0c;一直没空学。最近重学多项式&#xff0c;就重新搞了一下。 MTT 主要解决的是任意模数&#xff08;或者说是没有模数&#xff09;的多项式乘法&#xff0c;可以用于应对专门恶心人的毒瘤题。 首先&#xff0c;假设多项式次数 10510^5105,值…

在 VS Code 中轻松 review GitHub Pull Requests

相信大家在平时工作或者自己的项目中&#xff0c;一定都有在 GitHub 上进行 Code Review 的经历。对于韩老师来说&#xff0c;不论是平时工作的项目&#xff0c;还是自己的业余项目&#xff0c;代码基本都是在 GitHub 上。所以&#xff0c;在 GitHub 上进行 Pull Requests 的 C…

Codeforces Round #732 (Div. 2) C. AquaMoon and Strange Sort 思维

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你nnn个数&#xff0c;每个数初始方向是向右&#xff0c;每次可以交换相邻两个位置并且将这两个位置的方向调换&#xff0c;问这个序列的最终状态能否是非递减且方向都向右。 n≤1e5,ai≤1e5n\le1e5,a_i\l…

【CC November Challenge 2012】Arithmetic Progressions【分块】【FFT】

题意&#xff1a;给定长度为 nnn 的正整数序列 AAA,求满足 i<j<k,Aj−AiAk−Aji<j<k,A_j-A_iA_k-A_ji<j<k,Aj​−Ai​Ak​−Aj​ 的三元组个数。 n≤105,Ai≤3104n\leq 10^5,A_i\leq 3\times 10^4n≤105,Ai​≤3104 三个位置只有 jjj 限制比较紧&#xff0c…

火热的云原生到底是什么?一文了解云原生四要素!

所谓云原生&#xff0c;它不是一个产品&#xff0c;而是一套技术体系和一套方法论&#xff0c;而数字化转型是思想先行&#xff0c;从内到外的整体变革。更确切地说&#xff0c;它是一种文化&#xff0c;更是一种潮流&#xff0c;是云计算的一个必然导向。随着虚拟化技术的成熟…

Codeforces Round #732 (Div. 2) D. AquaMoon and Chess 组合数学 + 找规律

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你一个010101串&#xff0c;当且仅当某个111的某一边i1,i−1i1,i-1i1,i−1有111&#xff0c;这个111可以跟i2,i−2i2,i-2i2,i−2交换位置&#xff0c;问最终能产生多少状态。 n≤1e5n\le1e5n≤1e5 思路&a…

为什么说拥抱.NET CORE的时候到了

微软和社区已经做了大量艰苦的工作&#xff0c;使.Net Core成为市场上具有竞争力的框架&#xff0c;帮助开发人员快速开发具有最佳性能和可扩展性的强大应用程序。做的最棒的事情是.Net Framework开发人员不需要任何新知识来处理.Net Core。这也是开发人员在很短的时间内采用.N…

【HNOI2016】序列【莫队】【单调栈】【ST表】

题意&#xff1a;给定序列 aia_iai​&#xff0c;qqq 次询问 [l,r][l,r][l,r] 所有子区间最小值之和。 n,q≤105n,q\leq 10^5n,q≤105 这种题一眼看上去是离线线段树&#xff0c;但这题每移动一位要维护区间取 min⁡\minmin&#xff0c;历史值之和&#xff0c;非常不可做。 所…

湖南大学第十六届程序设计竞赛 B Yuki with emofunc and playf 同余最短路

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 初始有一个数111&#xff0c;你每次可以将其∗10*10∗10或者(x−1)(x-1)(x−1)&#xff0c;现在给你xxx&#xff0c;问最少经过多少步能到达nnn。 1≤n≤1e6,1≤m≤1e91\le n\le1e6,1\le m\le1e91≤n≤1e6,1…

【HNOI2019】白兔之舞【组合数学】【矩阵快速幂】【单位根反演】【Chirp Z-Transform】【原根】【MTT】

题意&#xff1a;有一张 (L1)n(L1)\times n(L1)n 个点的有向图&#xff0c;每个结点有二元组 (x,y)(0≤x≤L,1≤y≤n)(x,y)~(0\leq x\leq L,1\leq y\leq n)(x,y) (0≤x≤L,1≤y≤n) 表示。对于所有 (u1,v1),(u2,v2)(u_1,v_1),(u_2,v_2)(u1​,v1​),(u2​,v2​)&#xff0c;若 u…

程序员如何学习英语

首先&#xff0c;这不是一篇广告&#xff0c;虽然这个标题很像。其次&#xff0c;我的英语水平也很一般&#xff0c;所以更多的是谈谈一些失败的经历和思考&#xff0c;俗话说&#xff0c;成功的经验不可复制&#xff0c;失败的经验倒可以让我们少走弯路。英语的重要性毋庸置疑…

Educational Codeforces Round 111 (Rated for Div. 2) D. Excellent Arrays 组合数学

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你一个数组aia_iai​&#xff0c;定义一个数组是好的当且仅当对于所有iii都有ai!ia_i!iai​!i。定义f(a)f(a)f(a)表示数组aaa中i<j,aiajiji<j,a_ia_jiji<j,ai​aj​ij的(i,j)(i,j)(i,j)对数。定义…

使用Azure云原生构建博客是怎样一种体验?(上篇)

点击上方蓝字关注“汪宇杰博客”导语https://edi.wang我的网站是在.NET Core 平台上使用 C#语言编写的开源博客系统&#xff0c;运行于微软智慧云 Azure 国际版上。本文将重点介绍 Azure 的各项服务如何为博客带来丝滑体验与保驾护航。历史回顾我博客的历史可以追溯到2003年&am…

AtCoder Regular Contest 100 D - Equal Cut 思维 + 前缀和

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你一个数组aaa&#xff0c;你要将其分成四份&#xff0c;让这四份中和的最大值−-−最小值最小&#xff0c;输出这个最小值。 n≤2e5,ai≤1e9n\le2e5,a_i\le1e9n≤2e5,ai​≤1e9 思路&#xff1a; 直接枚…

【UOJ574】多线程计算【二元二项式反演】【定积分】【矩阵】【NTT 卷积】

题意&#xff1a;有 nmn\times mnm 的网格&#xff0c;每个结点在 [0,1)[0,1)[0,1) 内的一个随机时刻被点亮。有 hhh 个数对 xi,yix_i,y_ixi​,yi​&#xff0c;对于一个瞬间状态&#xff0c;如果存在一个 xi,yix_i,y_ixi​,yi​ 使得恰好有 xix_ixi​ 行 yiy_iyi​ 列被点亮&a…

Orleans 知多少 | 2. 核心概念一览

Orleans 术语解读上面这张图中包含了Orleans中的几个核心概念&#xff1a;GrainSiloOrleans ClusterOrleans Client从这张图&#xff0c;我们应该能理清他们之间的关系。Grain作为最小的执行单元Silo 是 Grain 的宿主运行环境&#xff0c;用来暴露具体的服务Orleans Server 提供…

Codeforces Round #587 (Div. 3) C. White Sheet 思维

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你一个白色的矩形和俩个黑色的矩形&#xff0c;问白色被黑色覆盖后还能不能看到。 思路&#xff1a; 经典被简单题卡。 一开始写了个自我感觉很对的做法&#xff0c;结果wa41wa41wa41&#xff0c;检查不…

【UOJ575】光伏元件【网络流建图】【上下界网络流】【费用流】

题意&#xff1a; nnn\times nnn 的 01 矩阵&#xff0c;对于 i∈[1,n]i \in [1,n]i∈[1,n] 有三个参数 li,li,kil_i,l_i,k_ili​,li​,ki​&#xff0c;表示第 iii 行&#xff0c;第 iii 列的 111 的个数分别在 [li,ri][l_i,r_i][li​,ri​] 中&#xff0c;且差的绝对值不超过…