poj3728 商务旅行
[Description]
小 T 要经常进行商务旅行,他所在的国家有 N 个城镇,标号为 1,2,3,...,N,这 N 个城镇构
成一棵树。每个城镇可以买入和卖出货物,同一城镇买入和卖出的价格一样,小 T 想从 a
走到 b,在这过程中,在某个城镇买入一个货物,然后在一个城镇卖出,可以是同一城镇买
入和卖出,使得收益最大,注意不能走回头路。
[Input]
第一行一个数 N,第二行 N 个数,第 i 个数表示城镇 i 买入和卖出货物的价格。
接下来 N – 1 行,每行两个数 a,b,表示 a 到 b 之间有一条双向的道路。
接下一行一个数 Q,表示有 Q 个询问,接下来 Q 行,每行两个数 x,y,表示要求小 T 从 x
到 y 的最大收益。
[Output]
对于每个询问,给出一个答案,各占一行。
[Sample Input]
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]
7
11
7
0
0
15
[Hint]
对于 50%的数据,0 < n <= 1000,0 < m <= 100
对于 100%的数据,0 < n <= 100000,0 < m <= 10000,0 <= 货物的价格 <= 10^8
设 fa[i][j]表示点 i 的第 2^j 个祖先
ma[i][j]表示点 i 到点 fa[i][j]的最大值。
mi[i][j]表示点 i 到点 fa[i][j]的最小值。
up[i][j]表示点 i 到点 fa[i][j]的最大获利。
down[i][j]表示点 fa[i][j]到点 i 的最大获利。
然后我们可以预处理出这四个数组。
即:
ma[x][i]=max(ma[fa[x][i-1]][i-1],ma[x][i-1]);
mi[x][i]=min(mi[fa[x][i-1]][i-1],mi[x][i-1]);
up[x][i]=max(max(up[fa[x][i-1]][i-1],up[x][i-1]),ma[fa[x][i-1]][i-1]-mi[x][i-1]);
down[x][i]=max(max(down[fa[x][i-1]][i-1],down[x][i-1]),ma[x][i-1]-mi[fa[x][i-1]][i-1]);
在走向最近公共祖先的路径上记录一下历史最小值,在远离最近公共祖先的路径上记录一下历史最大值(在途中和最大获利比较)。最后答案再和历史最大值-历史最小值比较一下即可
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 struct Node 7 { 8 int next,to; 9 }edge[300001]; 10 int head[100001],num,ans,dep[100001],val[100001],flag,n,Q; 11 int fa[100001][19],Min[100001][19],Max[100001][19],Up[100001][19],Down[100001][19]; 12 void add(int u,int v) 13 { 14 num++; 15 edge[num].next=head[u]; 16 head[u]=num; 17 edge[num].to=v; 18 } 19 void dfs(int x,int pa) 20 {int i; 21 if (dep[x]) return; 22 dep[x]=dep[pa]+1; 23 for (i=1;i<=18;i++) 24 { 25 fa[x][i]=fa[fa[x][i-1]][i-1]; 26 Max[x][i]=max(Max[x][i-1],Max[fa[x][i-1]][i-1]); 27 Min[x][i]=min(Min[x][i-1],Min[fa[x][i-1]][i-1]); 28 Up[x][i]=max(Up[x][i-1],Up[fa[x][i-1]][i-1]); 29 Up[x][i]=max(Up[x][i],Max[fa[x][i-1]][i-1]-Min[x][i-1]); 30 Down[x][i]=max(Down[x][i-1],Down[fa[x][i-1]][i-1]); 31 Down[x][i]=max(Down[x][i],Max[x][i-1]-Min[fa[x][i-1]][i-1]); 32 } 33 for (i=head[x];i;i=edge[i].next) 34 { 35 int v=edge[i].to; 36 if (v!=pa) 37 { 38 Max[v][0]=max(val[v],val[x]); 39 Min[v][0]=min(val[v],val[x]); 40 Up[v][0]=max(0,val[x]-val[v]); 41 Down[v][0]=max(0,val[v]-val[x]); 42 fa[v][0]=x; 43 dfs(v,x); 44 } 45 } 46 } 47 int LCA(int x,int y) 48 { 49 int i; 50 if (dep[x]<dep[y]) swap(x,y); 51 for (i=18;i>=0;i--) 52 if ((1<<i)<=dep[x]-dep[y]) 53 { 54 x=fa[x][i]; 55 } 56 if (x==y) 57 { 58 //cout<<"LCA:"<<' '<<x<<endl; 59 return x; 60 } 61 for (i=18;i>=0;i--) 62 if (fa[x][i]!=fa[y][i]) 63 { 64 x=fa[x][i]; 65 y=fa[y][i]; 66 } 67 x=fa[x][0]; 68 y=fa[y][0]; 69 //cout<<"LCA:"<<' '<<x<<endl; 70 return x; 71 } 72 void get_ans(int x,int y,int lca) 73 {int i; 74 int a=0,b=0,minv=2e9,maxv=0; 75 int small=2e9,large=0; 76 for (i=18;i>=0;i--) 77 if ((1<<i)<=dep[x]-dep[lca]) 78 { 79 b=max(b,Up[x][i]); 80 b=max(b,Max[x][i]-small); 81 small=min(small,Min[x][i]); 82 minv=min(minv,Min[x][i]); 83 x=fa[x][i]; 84 } 85 for (i=18;i>=0;i--) 86 if ((1<<i)<=dep[y]-dep[lca]) 87 { 88 a=max(a,Down[y][i]); 89 a=max(a,large-Min[y][i]); 90 large=max(large,Max[y][i]); 91 maxv=max(maxv,Max[y][i]); 92 y=fa[y][i]; 93 } 94 ans=max(a,max(b,maxv-minv)); 95 return; 96 } 97 int main() 98 {int i,u,v,x,y; 99 freopen("business.in","r",stdin); 100 freopen("business.out","w",stdout); 101 cin>>n; 102 memset(Min,127,sizeof(Min)); 103 for (i=1;i<=n;i++) 104 scanf("%d",&val[i]); 105 for (i=1;i<n;i++) 106 { 107 scanf("%d%d",&u,&v); 108 add(u,v);add(v,u); 109 } 110 dfs(1,0); 111 cin>>Q; 112 while (Q--) 113 { 114 scanf("%d%d",&x,&y); 115 if (x==y) printf("0\n"); 116 else 117 { 118 int lca=LCA(x,y); 119 get_ans(x,y,lca); 120 printf("%d\n",ans); 121 } 122 } 123 }