【codevs3305】水果姐逛水果街Ⅱ LCA
2015-10-18 20:05
330 查看
题目描述 Description
水果姐第二天心情也很不错,又来逛水果街。突然,cgh又出现了。cgh施展了魔法,水果街变成了树结构(店与店之间只有一条唯一的路径)。
同样还是n家水果店,编号为1~n,每家店能买水果也能卖水果,并且同一家店卖与买的价格一样。
cgh给出m个问题,每个问题要求水果姐从第x家店出发到第y家店,途中只能选一家店买一个水果,然后选一家店(可以是同一家店,但不能往回走)卖出去。求最多可以赚多少钱。
水果姐向学过oi的你求助。
输入描述 Input Description
第一行n,表示有n家店下来n个正整数,表示每家店一个苹果的价格。
下来n-1行,每行两个整数x,y,表示第x家店和第y家店有一条边。
下来一个整数m,表示下来有m个询问。
下来有m行,每行两个整数x和y,表示从第x家店出发到第y家店。
输出描述 Output Description
有m行。
每行对应一个询问,一个整数,表示面对cgh的每次询问,水果姐最多可以赚到多少钱。
样例输入 Sample Input
[code]10 16 5 1 15 15 1 8 9 9 15 1 2 1 3 2 4 2 5 2 6 6 7 4 8 1 9 1 10 6 9 1 5 1 1 7 3 3 1 1 3 6
样例输出 Sample Output
[code]7 11 7 0 0 15
数据范围及提示 Data Size & Hint
0<=苹果的价格<=10^80 < n<=200000
0 < m<=10000
不得不说这个lca真的好恶心!!
记录不知道多少个值:
[code]anc[x][i]:x往上(1<<i)的祖先。 maxn[x][i]:x到anc[x][i]的最大值。 minn[x][i]:x到anc[x][i]的最小值。 ans1[x][i]:从anc[x][i]走到x的答案。 ans2[x][i]:从x走到anc[x][i]的答案。
假设路线是x->y,并x在lca左边,y在lca右边。
这样,答案只会在:
[code]lca左边 lca右边 lca右边的最大值-lca左边的最小值
对于左边,要时刻用未来的最大值-历史的最小值更新答案。
对于右边,要时刻用历史的最大值-当前的最小值更新答案。
代码:
[code]#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; const int size=400010; const int INF=233333333; int head[size],nxt[size],to[size],tot=0; int num[size]; int maxn[size][30],minn[size][30],anc[size][30],ans1[size][30],ans2[size][30]; //ans1:从上到下 ans2:从下到上 int deep[size]; void build(int f,int t) { to[++tot]=t; nxt[tot]=head[f]; head[f]=tot; } void dfs(int u,int fa) { if(deep[u]) return ; deep[u]=deep[fa]+1; minn[u][0]=min(num[u],num[fa]); maxn[u][0]=max(num[u],num[fa]); ans1[u][0]=max(0,num[u]-num[fa]); ans2[u][0]=max(0,num[fa]-num[u]); anc[u][0]=fa; for(int i=1;anc[u][i-1];i++) { anc[u][i]=anc[anc[u][i-1]][i-1]; maxn[u][i]=max(maxn[u][i-1],maxn[anc[u][i-1]][i-1]); minn[u][i]=min(minn[u][i-1],minn[anc[u][i-1]][i-1]); ans1[u][i]=max( max(ans1[u][i-1],ans1[anc[u][i-1]][i-1]) , maxn[u][i-1]-minn[anc[u][i-1]][i-1] ); ans2[u][i]=max( max(ans2[u][i-1],ans2[anc[u][i-1]][i-1]) , maxn[anc[u][i-1]][i-1]-minn[u][i-1] ); } for(int i=head[u];i;i=nxt[i]) { int v=to[i]; dfs(v,u); } } int asklca(int x,int y) { int ans=0; if(deep[x]<deep[y]) swap(x,y); if(deep[x]>deep[y]) { int dd=deep[x]-deep[y]; for(int i=24;i>=0;i--) { if(dd&(1<<i)) { x=anc[x][i]; } } } if(x!=y) { for(int i=24;i>=0;i--) { if(anc[x][i]!=anc[y][i]) { x=anc[x][i]; y=anc[y][i]; } } } if(x==y) return x; else return anc[x][0]; } int ask(int x,int y) { int lca=asklca(x,y); int maxx=-INF,minnn=INF,ans=0; int dd1=deep[x]-deep[lca]; if(dd1>0) { for(int i=24;i>=0;i--) { if(dd1&(1<<i)) { ans=max(ans, max(ans2[x][i],maxn[x][i]-minnn) ); minnn=min(minn[x][i],minnn); x=anc[x][i]; } } } int dd2=deep[y]-deep[lca]; if(dd2>0) { for(int i=24;i>=0;i--) { if(dd2&(1<<i)) { ans=max(ans, max(ans1[y][i],maxx-minn[y][i]) ); maxx=max(maxn[y][i],maxx); y=anc[y][i]; } } } return max(ans,maxx-minnn); } int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&num[i]); } for(int i=1;i<=n-1;i++) { int a,b; scanf("%d%d",&a,&b); build(a,b); build(b,a); } dfs(1,0); int q; scanf("%d",&q); while(q--) { int x,y; scanf("%d%d",&x,&y); printf("%d\n",ask(x,y)); } return 0; }
相关文章推荐
- Hibernate学习笔记
- HVM的初始化状态
- 第十六篇:typef用法
- MFC程序内存不足问题
- 求一个非负整数数组中不相邻元素之和的最大值
- Sublime Text2配置过程
- Ajax使用的四大步骤
- php----网站架构简单了解
- 异常处理机制
- JavaScript(五) hasOwnProtype原型链 过滤
- 关于GridView控件中设置大小的问题
- Java开源 开源工作流
- 1-10的四则运算
- 使用xshell连接vmware虚拟机安装的centos服务器
- CALayer与UIView的关系
- 2015 Multi-University Training Contest 1
- 《拖延症再见》
- Android开发手记(11) 滑动条SeekBar
- [转]深入理解Java的接口和抽象类
- BAT脚本如何自动执行 adb shell 以后的命令