lca的好题!网上用st表和离线解的比较多,用树上倍增也是可以做的

不知道错在哪里,等刷完了这个专题再回来看

题解链接https://blog.csdn.net/Sd_Invol/article/details/9572423

/*
给一颗点权树,求出一个点对(x,y)之间的max{A,B,C}
A:x到lca路径上的最大差值
B:lca到y路径上的最大差值
C:x到y路径上的最大差值
需要维护的值,x结点到的祖先,x结点到祖先路径上的最大值,最小值,x结点到路径上的最大收益,最小收益(可以是负数)
对于每个询问x->y:A:x到祖先的最大收益
B:y到祖先的最小收益的负值
C:x到lca的最大值减去lca到y的最小值
*/
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define maxn 50005
struct Edge{
int x,next;
}e[maxn<<];
int head[maxn],tot,n,q;
inline void addedge(int u,int v){
e[tot].x=v;
e[tot].next=head[u];
head[u]=tot++;
}
int d[maxn],f[maxn][],a[maxn];//深度,祖先,点权
int fm[maxn][],fn[maxn][],sm[maxn][],sn[maxn][];//最大值,最小值,最大收益,最小收益
void init(){
tot=;
memset(head,-,sizeof head);
}
void dfs(int x,int fa,int dep){
d[x]=dep,f[x][]=fa;
for(int i=head[x];i!=-;i=e[i].next)
if(fa!=e[i].x) dfs(e[i].x,x,dep+);
}
int query(int x,int y){
int i,xx=,yy=,X=a[x],Y=a[y];//x侧最大收益,y侧最小收益,x侧最小值,y侧最大值
i=;
while(d[x]!=d[y]){//拉倒同一高度
if(abs(d[x]-d[y]) >= <<i)
if(d[y]<d[x])
xx=max(max(xx,sm[x][i]),fm[x][i]-X),X=min(X,fn[x][i]),x=f[x][i];
else
yy=min(min(yy,sn[y][i]),fn[y][i]-Y),Y=max(Y,fm[y][i]),y=f[y][i];
--i;
}
if(x==y) return max(max(xx,-yy),Y-X);
i=;
while(i>=){
if(f[x][i] && f[y][i] && f[x][i]!=f[y][i]){
xx=max(max(xx,sm[x][i]),fm[x][i]-X),X=min(X,fn[x][i]),x=f[x][i];
yy=min(min(yy,sn[y][i]),fn[y][i]-Y),Y=max(Y,fm[y][i]),y=f[y][i];
}
--i;
}
i=;//这里还要跳一次
xx=max(max(xx,sm[x][i]),fm[x][i]-X),X=min(X,fn[x][i]),x=f[x][i];
yy=min(min(yy,sn[y][i]),fn[y][i]-Y),Y=max(Y,fm[y][i]),y=f[y][i];
return max(max(xx,-yy),Y-X);
}
void work(){
int x,y;
init();
scanf("%d",&n);
for(int i=;i<=n;i++) scanf("%d",&a[i]);
for(int i=;i<n;i++){
scanf("%d%d",&x,&y);
addedge(x,y);addedge(y,x);
}
dfs(,,);
fm[][]=fn[][]=a[];
sm[][]=-<<;sn[][]=<<;
for(int i=;i<=n;i++){//先打初始状态
fm[i][]=max(a[i],a[f[i][]]);//和父亲比较
fn[i][]=min(a[i],a[f[i][]]);
sm[i][]=max(,a[f[i][]]-a[i]);//要么是0,要么赚了钱
sn[i][]=min(,a[f[i][]]-a[i]);//要么是0,要么是亏了钱
}
for(int j=;(<<j)<n;j++)//再打剩下状态
for(int i=;i<=n;i++){
int tmp=f[i][j-];//中间态
f[i][j]=f[tmp][j-];
fm[i][j]=max(fm[i][j-],fm[tmp][j-]);
fn[i][j]=min(fm[i][j-],fm[tmp][j-]);
sm[i][j]=max(max(sm[i][j-],sm[tmp][j-]),fm[tmp][j-]-fn[i][j-]);//最大收益要么是两段间的最大收益,要么是祖先段的最大收益减去子孙段的最小收益
sn[i][j]=min(min(sn[i][j-],sn[tmp][j-]),fn[tmp][j-]-fm[i][j-]);//最小收益相反
}
scanf("%d",&q);
while(q--){
scanf("%d%d",&x,&y);
printf("%d\n",query(x,y));
}
}
int main(){
work();
return ;
}

poj3728 倍增法lca 好题!的更多相关文章

  1. Codeforces 519E A and B and Lecture Rooms [倍增法LCA]

    题意: 给你一棵有n个节点的树,给你m次询问,查询给两个点,问树上有多少个点到这两个点的距离是相等的.树上所有边的边权是1. 思路: 很容易想到通过记录dep和找到lca来找到两个点之间的距离,然后分 ...

  2. 倍增法-lca codevs 1036 商务旅行

    codevs 1036 商务旅行  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题目描述 Description 某首都城市的商人要经常到各城镇去做生意 ...

  3. 倍增法lca

    ][N],siz[N];//rt数组需要在dfs之前置-1. void dfs(int pos,int deep){ dep[pos]=deep; siz[pos]=; for(edge *it=ad ...

  4. poj1470 LCA倍增法

    倍增法模板题 #include<iostream> #include<cstring> #include<cstdio> #include<queue> ...

  5. 最近公共祖先算法LCA笔记(树上倍增法)

    Update: 2019.7.15更新 万分感谢[宁信]大佬,认认真真地审核了本文章,指出了超过五处错误捂脸,太尴尬了. 万分感谢[宁信]大佬,认认真真地审核了本文章,指出了超过五处错误捂脸,太尴尬了 ...

  6. 浅谈倍增法求解LCA

    Luogu P3379 最近公共祖先 原题展现 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入格式 第一行包含三个正整数 \(N,M,S\),分别表示树的结点个数.询问 ...

  7. lca入门———树上倍增法(博文内含例题)

    倍增求LCA: father[i][j]表示节点i往上跳2^j次后的节点 可以转移为 father[i][j]=father[father[i][j-1]][j-1] 整体思路: 先比较两个点的深度, ...

  8. 倍增法求LCA(最近公共最先)

    对于有根树T的两个结点u.v,最近公共祖先x=LCA(u,v)表示一个结点x,满足x是u.v的祖先且x的深度尽可能大. 如图,根据定义可以看出14和15的最近公共祖先是10,   15和16的最近公共 ...

  9. hdu2586 lca倍增法

    倍增法加了边的权值,bfs的时候顺便把每个点深度求出来即可 #include<iostream> #include<cstring> #include<cstdio> ...

随机推荐

  1. 【已解决】ERR_BLOCKED_BY_XSS_AUDITOR:Chrome 在此网页上检测到了异常代码:解决办法

    工作中,用Selenium自动化填表并获取结果时,程序一直安静的读取数据库,网页填表,获取结果,存库,但跑着跑着突然报错了. 排查后,原来不是Selenium的问题,是数据比较特殊,带了个双引号,如下 ...

  2. 51Nod1376 (dp + BIT // cdq分治)

    https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1376 求LIS的数量. 乍一看觉得还是dp,仔细一看确实可以用dp做. ...

  3. 将本地的代码推送到公网的github账号去

    将本地的代码推送到公网的github账号去 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 最近工作上需要用到github账号,拜读了一位叫廖雪峰的大神的文档,把git的前世今生说的 ...

  4. python---redis中文操作与系统中文检测

    import redis import chardet r.set("name","我是在Py3保存的中文字符串") ret = r.get("nam ...

  5. 词典的实现(3)--使用JAVA类库ArrayList实现Map数据结构

    1,在词典的实现(2)-借助顺序表(数组)实现词典文章中使用了自定义的数组代替ArrayList,并实现了Map数据结构的基本功能.而借助JAVA类库ArrayList类的一些方法可以更加容易地实现M ...

  6. vue自学入门-3(vue第一个例子)

    1.安装后打开8080端口,http://localhost:8080/#/ 2.进入项目目录 2.默认路由 3.修改文件index.js 将Import HelloWorld一句修改为 import ...

  7. WINFROM窗体实现圆角

    首先我们先看看效果图 接下来我们看看怎么实现 先把窗体的FromBorderStyle属性改成None. 接下来登录窗体代码代码: 添加一个窗体Paint事件,引用using System.Drawi ...

  8. vue学习一:新建或打开vue项目(vue-cli2)

    vue-cli3的操作参考文章:vue/cli 3.0脚手架搭建,浅谈vue-cli 3 和 vue-cli 2的区别 1.前期准备: node.js环境,安装node npm或者cnpm(npm的淘 ...

  9. 【Udacity并行计算课程笔记】- Lesson 3 Fundamental GPU Algorithms (Reduce, Scan, Histogram)

    本周主要内容如下: 如何分析GPU算法的速度和效率 ​​3个新的基本算法:归约.扫描和直方图(Reduce.Scan.Histogram) 一.评估标准 首先介绍用于评估GPU计算的两个标准: ste ...

  10. 嵌入式Linux驱动笔记(十八)------浅析V4L2框架之ioctl【转】

    转自:https://blog.csdn.net/Guet_Kite/article/details/78574781 权声明:本文为 风筝 博主原创文章,未经博主允许不得转载!!!!!!谢谢合作 h ...