poj3728 The merchant 倍增LCA
来源:互联网 发布:南风知我意txt下载 编辑:程序博客网 时间:2024/05/16 07:48
给定一个点带权的树,有Q个询问。
一次询问求从X到Y的这条路径上,从一个点买从这个点之后的某个点卖,求最大收益,买必须再卖之前。
求倍增LCA的时候维护5个值
f ij : i的2^j级祖先
fm ij i到i的2^j级祖先的最大点权
fn ij i到i的2^j级祖先的最小点权
sm ij i到i的2^j级祖先的最大收益
sn ij i到i的2^j级祖先的最小收益
从x到y就看成了从x向上到LCA(x,y)向下到y,两条路径分开考虑最后再合并答案即可。
为什么要维护最小收益呢,因为从LCA(x,y)到y的过程就相当于是把从y到LCA(x,y)倒过来看,LCA(x,y)到y的最大值就是y到LCA(x,y)的最小值。
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <vector>#include <cstdlib>#include <cmath>#include <cctype>#include <queue>#include <stack>#include <utility>#include <map>#define pb push_back#define mp make_pair#define fi first#define se secondusing namespace std;#define N 50005int n , m , pre[N] , mcnt , Q;struct edge{ int x , next;}e[N << 1];int d[N] , f[N][16] , a[N];int fm[N][16] , fn[N][16] , sm[N][16] , sn[N][16] ;void dfs(int x , int fa , int dep){ d[x] = dep , f[x][0] = fa; for (int i = pre[x] ; ~i ; i = e[i].next) if (fa != e[i].x) dfs(e[i].x , x , dep + 1);}int query(int x , int y){ int i , xx = 0 , yy = 0 , X = a[x] , Y = a[y]; i = 15; while (d[x] != d[y]) { if (abs(d[x] - d[y]) >= 1 << 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 = 15; while (i >= 0) { 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 = 0; 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 i , j , x , y; scanf("%d",&n); for (i = 1 ; i <= n ; ++ i) scanf("%d",&a[i]); memset(pre , -1 , sizeof(pre)); for (i = 1 ; i < n ; ++ i) { scanf("%d%d",&x,&y); e[mcnt] = (edge) {y , pre[x]} , pre[x] = mcnt ++; e[mcnt] = (edge) {x , pre[y]} , pre[y] = mcnt ++; } dfs(1 , 0 , 0); fm[1][0] = fn[1][0] = a[1] , sm[1][0] = -1 << 30 , sn[1][0] = 1 << 30; for (i = 2 ; i <= n ; ++ i) { fm[i][0] = max(a[i] , a[f[i][0]]); fn[i][0] = min(a[i] , a[f[i][0]]); sm[i][0] = max(-a[i] + a[f[i][0]] , 0) , sn[i][0] = min(-a[i] + a[f[i][0]] , 0); } for (j = 1 ; 1 << j < n ; ++ j) for (i = 1 ; i <= n ; ++ i) { x = f[i][j - 1]; f[i][j] = f[x][j - 1]; fm[i][j] = max(fm[i][j - 1] , fm[x][j - 1]); fn[i][j] = min(fn[i][j - 1] , fn[x][j - 1]); sm[i][j] = max( max(sm[i][j - 1] , sm[x][j - 1]) , fm[x][j - 1] - fn[i][j - 1]); sn[i][j] = min( min(sn[i][j - 1] , sn[x][j - 1]) , fn[x][j - 1] - fm[i][j - 1]); } scanf("%d",&Q); while (Q --) { scanf("%d%d",&x,&y); printf("%d\n" , query(x , y)); }}int main(){ work(); return 0;}
- poj3728 The merchant 倍增LCA
- LCA 练习题:【POJ3728】The merchant
- poj3728 The merchant LCA+并查集
- poj3728 The merchant LCA(带权并查集?)
- poj3728 The merchant
- poj3728 The merchant
- 【POJ3728】The merchant
- POJ 3728 The merchant LCA+倍增dp
- poj3728 The merchant LCA+RMQ或 LCA+b并查集 好题!
- POJ 3728The merchant(dp+LCA+倍增)
- POJ 3728 The merchant(在线倍增LCA)
- The merchant - POJ 3728 LCA
- POJ 3728:The merchant LCA
- |poj 3728|LCA|The merchant
- poj 3728 The merchant(tarjan求lca)
- POJ 3728 The merchant (Tarjan LCA)
- *POJ 3728 - The merchant(LCA‘ Tarjan)
- POJ - 3728 The merchant(dp+LCA)
- 用自己写的方法实现n!
- 镜像问题
- Fatal signal 11 (SIGSEGV) at 0xdeadbaad (code=1) 指针内存问题
- uva297-四叉树
- HDU 4600
- poj3728 The merchant 倍增LCA
- HDU 4601
- poj3690 Constellations 字符串Hash
- 使用setContentView可以在Activity中动态切换显示的View
- HDU 4604
- HDU 4605
- 基于SUSE Linux做NFS文件挂载
- 怎样获得Win7禁止或启动的休眠的权限
- poj3068 "Shortest" pair of paths 费用流