bzoj 5341: [Ctsc2018]暴力写挂
Description

Solution
边分治+边分树合并
这个题很多做法都是启发式合并的复杂度的,都有点卡
以前有个套路叫做线段树合并优化启发式合并,消掉一个 \(log\)
这个题思路类似,建出边分树,通过一些操作把它变成线段树,就可以线段树合并了
首先边分树的相关定理:
如果一棵包含 \(N\) 个结点的树中每个点的度均不大于 \(D\),那么存在一条边,使得分出的两棵子树的结点个数在 \([N/(D+1),N*D/(D+1)]\)
那么边分树的深度和度数是相关的,我们只需要通过加虚点把这棵树变成二叉树就好了

回到这个题:
枚举第二棵树的 \(lca\) , 然后剩下的就是在第二棵树中选出在第一棵树中 \(dep[x]+dep[y]-dep[lca(x,y)]\) 的最大值
我们发现这个要求的东西就是 \(x,y\) 到根的路径的交,所以可以不考虑第一棵树的 \(lca\) 了
其中 \(x,y\) 都来自这个 \(lca\) 的不同子树内
每次插入一个点就像线段树那样更新就行了,不同的是你不能准确定位到这个叶子节点,你需要在 \(build\) 的时候顺便存一下对应关系
枚举第二棵树的 \(lca\) 再合并子树的边分树,顺便更新一下答案就行了
#include<bits/stdc++.h>
#define vc vector<edge>::iterator
#define pb push_back
using namespace std;
typedef long long ll;
const int N=750000,M=8510000,T=N*2;
int n,V,sz[N],sum,son[N]={N},val[T],ls[T],rs[T],dep[N],fa[T],tt=0;
ll f[N][20],dis[N],fl[M],fr[M],ans=0,D;int lm[M],rm[M],rt[N/2],id[M];
struct edge{
int x,v;
edge(){}
edge(int _x,int _v){x=_x;v=_v;}
}q[N];
vector<edge>G1[N],G2[N/2];
inline void add(int x,int y,int z,vector<edge>*G){
G[x].pb(edge(y,z));G[y].pb(edge(x,z));
}
inline void build(int x,int last){
for(vc it=G1[x].begin();it!=G1[x].end();++it){
if(it->x==last)continue;
dis[it->x]=dis[x]+it->v;build(it->x,x);
}
int l=1,r=0;edge u,v;
for(vc it=G1[x].begin();it!=G1[x].end();++it)if(it->x!=last)q[++r]=*it;
while(l+2<=r){
int o=++V;u=q[l++],v=q[l++];
add(o,u.x,u.v,G1);add(o,v.x,v.v,G1);
q[++r]=edge(o,0);
}
vector<edge>().swap(G1[x]);
while(l<=r)add(x,q[l].x,q[l].v,G1),l++;
}
inline void getdis(int x,int last,int d){
for(vc it=G1[x].begin();it!=G1[x].end();++it){
if(it->x==last || it->x==-1)continue;
f[it->x][d]=f[x][d]+it->v;getdis(it->x,x,d);
}
}
inline void getedge(int x,int last,int &ex,int &ey){
sz[x]=1;
for(int i=G1[x].size()-1,u;i>=0;i--){
if((u=G1[x][i].x)==last || u==-1)continue;
getedge(u,x,ex,ey);sz[x]+=sz[u];
if(son[u]<son[ey])ex=x,ey=u;
}
son[x]=abs(sum-2*sz[x]);
}
inline int solve(int x,int S,int d){
if(S==1){dep[x]=d;return x;}
int ex=0,ey=0,o=++V;
getdis(x,x,d);
sum=S;getedge(x,x,ex,ey);
for(vc it=G1[ex].begin();it!=G1[ex].end();++it)
if(it->x==ey){val[o]=it->v;it->x=-1;break;}
for(vc it=G1[ey].begin();it!=G1[ey].end();++it)
if(it->x==ex){it->x=-1;break;}
fa[ls[o]=solve(ex,S-sz[ey],d+1)]=o;
fa[rs[o]=solve(ey,sz[ey],d+1)]=o;
return o;
}
inline int ins(int x){
for(int i=dep[x],u=x,la=x;i>=1;i--){
id[++tt]=fa[x];fl[tt]=fr[tt]=-1ll<<60;
if(ls[fa[x]]==x)fl[tt]=max(fl[tt],dis[u]+f[u][i]),lm[tt]=la;
if(rs[fa[x]]==x)fr[tt]=max(fr[tt],dis[u]+f[u][i]),rm[tt]=la;
la=tt;x=fa[x];
}
return tt;
}
inline int merge(int x,int y){
if(!x||!y)return x+y;
ans=max(ans,(fl[x]+fr[y]+val[id[x]])/2-D);
ans=max(ans,(fl[y]+fr[x]+val[id[x]])/2-D);
fl[x]=max(fl[x],fl[y]);fr[x]=max(fr[x],fr[y]);
lm[x]=merge(lm[x],lm[y]);rm[x]=merge(rm[x],rm[y]);
return x;
}
inline void dfs(int x,int last,ll d){
rt[x]=ins(x);ans=max(ans,dis[x]-d);
for(vc it=G2[x].begin();it!=G2[x].end();++it){
if(it->x==last)continue;
dfs(it->x,x,d+it->v);D=d;
rt[x]=merge(rt[x],rt[it->x]);
}
}
int main(){
freopen("pp.in","r",stdin);
freopen("pp.out","w",stdout);
cin>>n;V=n;
int x,y,z;
for(int i=1;i<n;i++)scanf("%d%d%d",&x,&y,&z),add(x,y,z,G1);
for(int i=1;i<n;i++)scanf("%d%d%d",&x,&y,&z),add(x,y,z,G2);
build(1,1);solve(1,V,0);dfs(1,1,0);
cout<<ans<<endl;
return 0;
}
bzoj 5341: [Ctsc2018]暴力写挂的更多相关文章
- BZOJ5341: [Ctsc2018]暴力写挂
BZOJ5341: [Ctsc2018]暴力写挂 https://lydsy.com/JudgeOnline/problem.php?id=5341 分析: 学习边分治. 感觉边分治在多数情况下都能用 ...
- [CTSC2018]暴力写挂——边分树合并
[CTSC2018]暴力写挂 题面不错 给定两棵树,两点“距离”定义为:二者深度相加,减去两棵树上的LCA的深度(深度指到根节点的距离) 求最大的距离. 解决多棵树的问题就是降维了. 经典的做法是边分 ...
- [LOJ#2553][CTSC2018]暴力写挂
[LOJ#2553][CTSC2018]暴力写挂 试题描述 temporaryDO 是一个很菜的 OIer .在 4 月,他在省队选拔赛的考场上见到了<林克卡特树>一题,其中 \(k = ...
- BZOJ5341[Ctsc2018]暴力写挂——边分治+虚树+树形DP
题目链接: CSTC2018暴力写挂 题目大意:给出n个点结构不同的两棵树,边有边权(有负权边及0边),要求找到一个点对(a,b)满足dep(a)+dep(b)-dep(lca)-dep'(lca)最 ...
- [CTSC2018]暴力写挂
题目描述 www.lydsy.com/JudgeOnline/upload/201805/day1(1).pdf 题解 首先来看这个我们要最大化的东西. deep[u]+deep[v]-deep[lc ...
- UOJ400/LOJ2553 CTSC2018 暴力写挂 边分治、虚树
传送门--UOJ 传送门--LOJ 跟隔壁通道是一个类型的 要求的式子中有两个LCA,不是很方便,因为事实上在这种题目中LCA一般都是枚举的对象-- 第二棵树上的LCA显然是动不了的,因为没有其他的量 ...
- 并不对劲的bzoj5341:loj2553:uoj400:p4565:[Ctsc2018]暴力写挂
题目大意 有两棵\(n\)(\(n\leq366666\))个节点的树,\(T\)和\(T'\),有边权 \(dep(i)\)表示在\(T\)中\(i\)号点到\(1\)号点的距离,\(dep'(i) ...
- 题解 「CTSC2018暴力写挂」
题目传送门 题目大意 给出两个大小为 \(n\) 的树,求出: \[\max\{\text{depth}(x)+\text{depth}(y)-\text{depth}(\text{LCA}(x,y) ...
- 【CTSC2018】暴力写挂(边分治,虚树)
[CTSC2018]暴力写挂(边分治,虚树) 题面 UOJ BZOJ 洛谷 题解 发现第二棵树上的\(LCA\)的深度这玩意没法搞,那么枚举在第二棵树上的\(LCA\). 然后剩下的部分就是\(dep ...
随机推荐
- MVC批量上传文件
初始图片: 选中图片后 ---------------------------------------------------------------------------------- 前端代码 ...
- AJPFX简评:MT5平台
MetaTrader 5全面改进的图表和扩展的功能 MetaTrader软件开发商在MT4获得全球交易商全面好评之后,又再次研发推出了更为先进的MT5交易软件. MT5的主要特征●改进的图表和即时 ...
- Sorted方法排序用法
listA = [3,4,5,3,2,1,] print(sorted(listA)) # [1, 2, 3, 3, 4, 5] listB =["a","z" ...
- 萝卜保卫战3内购破解+Toast窗口增加(Love版)
涉及到一些不同的破解的方法,以及不同的破解思路,还有一些重要权限的删除等. 作者:HAI_ 这次目标是经常玩的萝卜保卫战,不知不觉,已经更新到3了.详细分析请参考https://bbs.ichunqi ...
- jquery ajax在跨域访问post请求的时候,包括ie9以下的浏览器无效,其他浏览器正常
最近做的一个项目,原先没有要求兼容IE9以下,所以在写代码的时候也没有打开IE9以下去测试,这两天要去做IE9以下的兼容,在IE9以下打开本地的项目发现数据请求不成功,而通过发布道服务器上的链接打开是 ...
- 【NOIP2013】 火柴排队 贪心+splay
这题为啥我写得这么复杂. 首先我们不难发现,我们将序列$a$和序列$b$排序,考虑两序列内无相同元素,那么最小值显然为$\sum_{i=1}^{n} (a_i-b_i)^2$. 下面考虑做法 首先,我 ...
- bootstrap-validator
使用bootstrap-validator挺多的,虽然自己写认证并不复杂,我一向喜欢现成的控件,原因是风格一致,不容易出错. 这个是接口文档:http://bv.doc.javake.cn/setti ...
- Linux实用指令
Linux实用指令 Rpm&Yum 一种用于互联网下载包的打包和安装工具,它包含某些Linux分发版中,它生产具有 .rpm 扩展名的文件.RPM 是 RedHat Package Man ...
- 剑指offer五十二之正则表达式匹配
一.题目 请实现一个函数用来匹配包括'.'和'*'的正则表达式.模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次). 在本题中,匹配是指字符串的所有字符匹配整个模式 ...
- 剑指offer二十八之数组中出现次数超过一半的数字
一.题目 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2. ...