poj3728 The merchant
题目:The merchant
题目描述:给出一棵有n个带权(price)节点的树(结点数n<=50000),给出m组询问{v,u},询问从v到u中差最多是多少(询问次数m<=50000)。
分析:
(1)算法一:最朴素的方法是从v到u完整的访问一遍,枚举一个在{v,u}这条路径上的点o作为卖出点x,求出{v,o}这条路的最小值y作为买入点,{x-y}的最大值即为所求结果。
(2)分析算法一:对于{v,o}这条路的最小值y,要使得{y-x}最大,那x必然是{o.u}的最大值。{v,u}中的差必然是{v,o}的差、{o,u}的差、{o.u}的最大值-{v,o}的最小值中取最大值。可以采取分治算法。
(3)算法二:把{v,u}的最近公共祖先lca最作为o分治算法的分割点。{v,u}中的差是{v,lca}的差、{lca,u}的差、{lca.u}的最大值-{v,lca}的最小值中取最大值。问题转化为快速计算{v,lca}的差,{lca,u}的差,{lca,u}的最大值,{v,lca}的最小值,仍然采用分治思想,利用倍增进行预处理和加速计算。
(4)算法三:由于询问没有相关性,而且所有询问在一开始就已经知道,可以离线计算。采用Tarjan算法,用并查集维护{v,lca}的差,{lca,u}的差,{lca,u}的最大值,{v,lca}的最小值。
(5)算法二和算法三均利用了分析二的思路。
(6)扩展:问题中的树如果退化成一条链,有其他做法。用一个新序列$w_2-w_1,w_3-w_2 ,\cdots, w_n-w_{n-1}$,这样只需要求得询问区间最大子段和即为结果Max-Min了,可以采用线段树去加速计算,做法类似{USACO 2008 Feb Hotel}一题。
代码:
算法二:
1 #include <cstdio> 2 #include <algorithm> 3 const int Inf=1e9; 4 int Tval[50005],Tdep[50005],Tfa[50005][21]; 5 int Tmin[50005][21],Tmax[50005][21],Tup[50005][21],Tdown[50005][21]; 6 int size,first[50005]; 7 struct Edge{int to,next;}e[100005]; 8 int Read(){ 9 int ch='@',t=0; 10 for(;ch<48 || 57<ch;ch=getchar()); 11 for(;47<ch && ch<58;ch=getchar())t=t*10+ch-48; 12 return t; 13 } 14 inline int max(int x,int y) {x-=y;return y+(x&(~(x>>31)));} 15 inline int min(int x,int y) {x-=y;return y+(x&(x>>31));} 16 void addedge(int x,int y){ 17 e[++size].to=y;e[size].next=first[x];first[x]=size; 18 e[++size].to=x;e[size].next=first[y];first[y]=size; 19 } 20 void LcaInit(int v){ 21 for(int i=1,j,k,tv;i<17;++i){ 22 Tfa[v][i]=Tfa[Tfa[v][i-1]][i-1]; 23 Tmin[v][i]=min(Tmin[v][i-1],Tmin[Tfa[v][i-1]][i-1]); 24 Tmax[v][i]=max(Tmax[v][i-1],Tmax[Tfa[v][i-1]][i-1]); 25 Tup[v][i]=max(max(Tup[v][i-1],Tup[Tfa[v][i-1]][i-1]),Tmax[Tfa[v][i-1]][i-1]-Tmin[v][i-1]); 26 Tdown[v][i]=max(max(Tdown[v][i-1],Tdown[Tfa[v][i-1]][i-1]),Tmax[v][i-1]-Tmin[Tfa[v][i-1]][i-1]); 27 } 28 for(int i=first[v],u;i;i=e[i].next){ 29 u=e[i].to;if(u==Tfa[v][0])continue; 30 Tfa[u][0]=v; 31 Tdep[u]=Tdep[v]+1; 32 Tmin[u][0]=min(Tval[u],Tval[v]); 33 Tmax[u][0]=max(Tval[u],Tval[v]); 34 Tup[u][0]=max(0,Tval[v]-Tval[u]); 35 Tdown[u][0]=max(0,Tval[u]-Tval[v]); 36 LcaInit(u); 37 } 38 } 39 int GetLca(int v,int u){ 40 if(Tdep[v]<Tdep[u])std::swap(v,u); 41 for(int i=16;i>=0;--i) 42 if((Tdep[v]-Tdep[u])&(1<<i))v=Tfa[v][i]; 43 if(v==u)return v; 44 for(int i=16;i>=0;--i) 45 if(Tfa[v][i]!=Tfa[u][i]){v=Tfa[v][i];u=Tfa[u][i];} 46 return Tfa[v][0]; 47 } 48 int GetAns(int v,int u){ 49 int lca=GetLca(v,u); 50 int Min=Inf,Max=0,ans=0; 51 for(int i=16;i>=0;--i) 52 if((Tdep[v]-Tdep[lca])&(1<<i)){ 53 ans=max(ans,max(Tup[v][i],Tmax[v][i]-Min)); 54 Min=min(Min,Tmin[v][i]); 55 v=Tfa[v][i]; 56 } 57 for(int i=16;i>=0;--i) 58 if((Tdep[u]-Tdep[lca])&(1<<i)){ 59 ans=max(ans,max(Tdown[u][i],Max-Tmin[u][i])); 60 Max=max(Max,Tmax[u][i]); 61 u=Tfa[u][i]; 62 } 63 return max(ans,Max-Min); 64 } 65 int main(){ 66 //freopen("in.txt","r",stdin); 67 //freopen("out.txt","w",stdout); 68 int n,q; 69 n=Read(); 70 for(int i=1;i<=n;++i) 71 Tval[i]=Read(); 72 for(int i=1,a,b;i<n;++i){ 73 a=Read();b=Read(); 74 addedge(a,b); 75 } 76 LcaInit(1); 77 q=Read(); 78 for(int i=1,a,b,ans;i<=q;++i){ 79 a=Read();b=Read(); 80 ans=GetAns(a,b); 81 printf("%d\n",ans); 82 } 83 //fclose(stdin);fclose(stdout); 84 return 0; 85 }
算法三:
1 #include <cstdio> 2 #include <algorithm> 3 const int Inf=1e9; 4 int Rt[50005]; 5 bool vis[50005]; 6 int Tmin[50005],Tmax[50005],Tup[50005],Tdown[50005]; 7 int Gsize,Qsize,Asize,Gfirst[50005],Qfirst[50005],Afirst[50005]; 8 struct GEdge{int to,next;}Ge[100005]; 9 struct QEdge{int to,id,next;}Qe[100005]; 10 struct AEdge{int id,next;}Ae[100005]; 11 struct Query{int u,v,ans;}Que[100005]; 12 int Read(){ 13 int ch='@',t=0; 14 for(;ch<48 || 57<ch;ch=getchar()); 15 for(;47<ch && ch<58;ch=getchar())t=t*10+ch-48; 16 return t; 17 } 18 inline int max(int x,int y) {x-=y;return y+(x&(~(x>>31)));} 19 inline int min(int x,int y) {x-=y;return y+(x&(x>>31));} 20 void Gaddedge(int x,int y){ 21 Ge[++Gsize].to=y;Ge[Gsize].next=Gfirst[x];Gfirst[x]=Gsize; 22 Ge[++Gsize].to=x;Ge[Gsize].next=Gfirst[y];Gfirst[y]=Gsize; 23 } 24 void Qaddedge(int x,int y,int id){ 25 Qe[++Qsize].to=y;Qe[Qsize].id=id;Qe[Qsize].next=Qfirst[x];Qfirst[x]=Qsize; 26 Qe[++Qsize].to=x;Qe[Qsize].id=id;Qe[Qsize].next=Qfirst[y];Qfirst[y]=Qsize; 27 } 28 void Aaddedge(int x,int id){ 29 Ae[++Asize].id=id;Ae[Asize].next=Afirst[x];Afirst[x]=Asize; 30 } 31 int GetRt(int v){ 32 if(Rt[v]==v)return v; 33 int fa=Rt[v]; 34 Rt[v]=GetRt(Rt[v]); 35 Tup[v]=max(max(Tup[v],Tup[fa]),Tmax[fa]-Tmin[v]); 36 Tdown[v]=max(max(Tdown[v],Tdown[fa]),Tmax[v]-Tmin[fa]); 37 Tmin[v]=min(Tmin[v],Tmin[fa]); 38 Tmax[v]=max(Tmax[v],Tmax[fa]); 39 return Rt[v]; 40 } 41 void Tarjan(int v){ 42 vis[v]=true; 43 for(int i=Qfirst[v],u,lca;i;i=Qe[i].next){ 44 u=Qe[i].to;if(!vis[u])continue; 45 lca=GetRt(u); 46 Aaddedge(lca,Qe[i].id); 47 } 48 for(int i=Gfirst[v],u;i;i=Ge[i].next){ 49 u=Ge[i].to;if(vis[u])continue; 50 Tarjan(u); 51 Rt[u]=v; 52 } 53 for(int i=Afirst[v],id,tv,tu;i;i=Ae[i].next){ 54 id=Ae[i].id;tv=Que[id].v;tu=Que[id].u; 55 GetRt(tv);GetRt(tu); 56 Que[id].ans=max(max(Tup[tv],Tdown[tu]),Tmax[tu]-Tmin[tv]); 57 } 58 } 59 int main(){ 60 //freopen("in.txt","r",stdin); 61 //freopen("out.txt","w",stdout); 62 int n,q; 63 n=Read(); 64 for(int i=1;i<=n;++i) 65 Rt[i]=i; 66 for(int i=1;i<=n;++i) 67 Tmin[i]=Tmax[i]=Read(); 68 for(int i=1,a,b;i<n;++i){ 69 a=Read();b=Read(); 70 Gaddedge(a,b); 71 } 72 q=Read(); 73 for(int i=1;i<=q;++i){ 74 Que[i].v=Read();Que[i].u=Read(); 75 Qaddedge(Que[i].v,Que[i].u,i); 76 } 77 Tarjan(1); 78 for(int i=1;i<=q;++i) 79 printf("%d\n",Que[i].ans); 80 //fclose(stdin);fclose(stdout); 81 return 0; 82 }