题目梗概

给出两棵1为根的树,求\(d[x]+d[y]-d[lca(x,y)]-d'[lca(x,y)]\)的最大值

解题思路

套路化简之后\((d[x]+d[y]+dis(x,y)-2*d'[lca(x,y)])/2\)

第二棵树上的lca化不掉,所以考虑在第二棵上枚举lca

先说说这题的解法,边分树的合并.

边分和点分有什么区别,边分在合并类似\(d[x]+d[y]+dis(x,y)\)这种贡献是很方便,只要记录一条边两端的点集中\(d[x]+dis(x,u)\)最大值即可,而点分合并这种贡献时复杂度与度数有关.

所以我们边分治第一棵树,建出边分树之后,遍历第二棵树,每次加入一个点,在边分树上维护答案

考虑左右儿子的答案如何合并,因为边分树是二叉树,像线段树一样合并即可,复杂度\(O(n\) \(log n)\).

边分治:将原图转成二叉树(保证复杂度),每次找左右两端节点数最大值最小的边分开即可.

#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=370005;
const LL INF=(LL)1e18;
inline int _read(){int num=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9') num=num*10+ch-48,ch=getchar();return f*num;
}
struct jz{int x,y,w;jz(int x=0,int y=0,int w=0):x(x),y(y),w(w){}
};
int lnk[maxn<<2],son[maxn<<3],nxt[maxn<<3],w[maxn<<3],tot=1;
int n,cnt,zo,rx,ry,mi,rh,s[maxn<<2],rs[maxn<<3],ls[maxn<<3],d[maxn<<2],val[maxn<<3],fa[maxn<<3];
int rt[maxn],id,lc[maxn*46],rc[maxn*46],h[maxn*46];
LL rw[maxn*46],lw[maxn*46],dis[23][maxn<<2],ans=-INF;
vector<jz> Q;
bool vis[maxn<<3];
void add(int x,int y,int z){nxt[++tot]=lnk[x];lnk[x]=tot;son[tot]=y;w[tot]=z;}
void DFS(int x,int fa){int pre=x;for (int j=lnk[x];j;j=nxt[j]) if (son[j]!=fa){Q.push_back(jz(pre,son[j],w[j]));Q.push_back(jz(pre,++cnt,0));pre=cnt;DFS(son[j],x);}
}
void get_ro(int x,int fa,int dep,int lst){s[x]=1;for (int j=lnk[x];j;j=nxt[j]) if (!vis[j]&&son[j]!=fa){dis[dep][son[j]]=dis[dep][x]+w[j];get_ro(son[j],x,dep,j),s[x]+=s[son[j]];}int w=max(zo-s[x],s[x]);if (w<=mi) mi=w,rx=x,ry=fa,rh=lst;
}
int work(int x,int dep,int sz){if (sz<=1) return d[x]=dep,x;mi=zo=sz;int now=++cnt;get_ro(x,0,dep,0);vis[rh]=vis[rh^1]=1;val[now]=w[rh];int X=rx,Y=ry;rs[now]=work(Y,dep+1,sz-s[X]);ls[now]=work(X,dep+1,s[X]);fa[ls[now]]=fa[rs[now]]=now;return now;
}
int add(int x){int lst=0,now=x;for (int i=d[x];i;i--){h[++id]=fa[now];lw[id]=rw[id]=-INF; if (now==ls[fa[now]]) lw[id]=dis[i][x]+dis[0][x],lc[id]=lst;if (now==rs[fa[now]]) rw[id]=dis[i][x]+dis[0][x],rc[id]=lst;lst=id;now=fa[now];}return id;
}
void merge(int &x,int y,LL dep){if (!x||!y){x=x+y;return;}ans=max(ans,lw[x]+rw[y]+val[h[x]]-dep);ans=max(ans,lw[y]+rw[x]+val[h[x]]-dep);lw[x]=max(lw[x],lw[y]);rw[x]=max(rw[x],rw[y]);merge(lc[x],lc[y],dep);merge(rc[x],rc[y],dep);
}
void solve(int x,int fa,LL dep){rt[x]=add(x);ans=max(ans,dis[0][x]*2-dep*2);for (int j=lnk[x];j;j=nxt[j]) if (son[j]!=fa){solve(son[j],x,dep+w[j]);merge(rt[x],rt[son[j]],dep*2);}}
int main(){freopen("exam.in","r",stdin);freopen("exam.out","w",stdout);n=_read();cnt=n;for (int i=1;i<n;i++){int x=_read(),y=_read(),z=_read();add(x,y,z);add(y,x,z);}DFS(1,0);memset(lnk,0,sizeof(lnk));tot=1;for (int i=0;i<Q.size();i++) add(Q[i].x,Q[i].y,Q[i].w),add(Q[i].y,Q[i].x,Q[i].w);work(1,0,cnt);memset(lnk,0,sizeof(lnk));tot=1;for (int i=1;i<n;i++){int x=_read(),y=_read(),z=_read();add(x,y,z);add(y,x,z);}solve(1,0,0);printf("%lld\n",ans/2);return 0;
} 

转载于:https://www.cnblogs.com/CHNJZ/p/10554011.html

[边分治+线段树合并]「CTSC2018」暴力写挂相关推荐

  1. [BJWC2018]Border 的四种求法(后缀自动机+链分治+线段树合并)

    题目描述 给一个小写字母字符串 S ,q 次询问每次给出 l,r ,求 s[l..r] 的 Border . Border: 对于给定的串 s ,最大的 i 使得 s[1..i] = s[|s|-i+ ...

  2. [BJOI2017]树的难题 点分治,线段树合并

    [BJOI2017]树的难题 LG传送门 点分治+线段树合并. 我不会写单调队列,所以就写了好写的线段树. 考虑对于每一个分治中心,把出边按颜色排序,这样就能把颜色相同的子树放在一起处理.用一棵动态开 ...

  3. P5327-[ZJOI2019]语言【线段树合并,LCA】

    正题 题目链接:https://www.luogu.com.cn/problem/P5327 题目大意 给出nnn个点的一棵树,和mmm条路径,求有多少个点对至少存在一条路径经过它们. 1≤n,m≤1 ...

  4. loj2537 「PKUWC2018」Minimax 【概率 + 线段树合并】

    题目链接 loj2537 题解 观察题目的式子似乎没有什么意义,我们考虑计算出每一种权值的概率 先离散化一下权值 显然可以设一个\(dp\),设\(f[i][j]\)表示\(i\)节点权值为\(j\) ...

  5. 线段树合并与分裂维护树上最长上升子序列 + 点分治删点 ---- 2021 牛客多校第一场 C - Cut the tree(详解)

    题目大意: 给你一个树,树上每个点都有一个权值valnodeval_{node}valnode​,路径(u,v)(u,v)(u,v) 上所有点按顺序有序序列,令f(u,v)f(u,v)f(u,v)是这 ...

  6. 数据结构之线段树合并——永无乡,Lomsat gelral,Tree Rotations,Tree Rotations Escape Through Leaf

    文章目录 [HNOI2012]永无乡 Lomsat gelral 「POI2011 R2 Day2」旋转树木 Tree Rotations Escape Through Leaf 线段树合并与 fhq ...

  7. Loj #2554. 「CTSC2018」青蕈领主

    Loj #2554. 「CTSC2018」青蕈领主 题目描述 "也许,我的生命也已经如同风中残烛了吧."小绿如是说. 小绿同学因为微积分这门课,对"连续"这一概 ...

  8. BZOJ2212——线段树合并

    学习线段树合并,以这道题为契机 多谢这篇博客 这里是通过对线段树合并时,顺手统计了对于一颗子树内,是否反转两种情况的逆序对数 这里只对代码进行详细分析,见注解好了 1 #include<cstd ...

  9. P3714 [BJOI2017]树的难题(点分治/线段树/单调队列)

    P3714 [BJOI2017]树的难题 求解树上长度在L到R的树链中颜色段权值和最大的链. 首先求解树上链的问题,而且限制了链的长度,那么我们需要点分治处理,然后考虑每次分治,我们可以把链分成两类, ...

最新文章

  1. gradle 构建完成自动删除_Gradle 6.6 RC6 发布,引入配置缓存特性,大幅提升构建性能
  2. dynamic 仪表板_仪表板完成百万美元交易
  3. 【STC15库函数上手笔记】9、硬件SPI
  4. 弹性负载均衡:负载无限,均衡有道【华为云分享】
  5. 记录一次linux病毒清除过程
  6. 剑指offer面试题[14]-调整数组顺序使奇数位于偶数前面
  7. [paper reading] CenterNet (Object as Points)
  8. Java编程思想精彩评注分享之二
  9. 台电tbook10s官方固件_【11月1日】台电官方系统固件更新
  10. c语言逻辑运算符用法大全,C语言逻辑运算符介绍和示例
  11. Win7、Win10封装系统制作系统镜像,操作流程#gho
  12. 《C语言程序设计》江宝钏主编-习题6-1-温度转换
  13. 安卓中动态生成界面布局
  14. 蓝桥杯国王的烦恼java,国王的烦恼 蓝桥杯
  15. PaddleOCR车牌检测识别训练、部署
  16. github.io使用方法
  17. Python多个数组合并(拼接)为一个数组
  18. Myeclipse2019使用官方汉化包说明
  19. 人工智能安防初创公司澎思科技宣布完成千万级天使轮融资 洪泰基金领投
  20. 大学生交友平台——项目启动篇

热门文章

  1. 查询sql语句是否使用索引
  2. 重读经典:《Deep Residual Learning for Image Recognition》
  3. W10的服务器正在运行,win10开机提示服务器正在运行中的解决教程
  4. php测试插入,php – 使用Symfony测试数据库插入
  5. android实现电话功能实验报告,安卓开发实验报告-20210407005833.docx-原创力文档
  6. dell服务器T100无法进入系统,DELL服务器开机Alert!Cover was previously removed F1
  7. 判断一个字符串大写小写,和数字出现的次数
  8. oracle更换rac节点,Oracle-rac 更改VIP地址—2节点的
  9. org.hibernate.LazyInitializationException: could not initialize proxy - no Session
  10. Java中如何实现每天定时对数据库的操作