题意很简单
给一个树(n < 5w) 每个点有个权值,代表商品价格
若干个询问(5w)
对每个询问,问的是从u点走到v点(简单路径),商人在这个路径中的某点买入商品,然后在某点再卖出商品, 最大可能是多少
注意一条路径上只能买卖一次,先买才能卖
-
*分析:先求出点u,v的最近公共祖先f,然后求u->f->v的利润最大值maxval
-
对于这个maxval可能有三种情况:
-
1:maxval是u->f的maxval
-
2:maxval是f->v的maxval
-
3:maxval是u->f的最小w[i]减去f->v的最大w[i]
-
分析到这很明显需要设置4个变量来求maxval:
-
up[u]表示u->f的最大maxval
-
down[u]表示f->u的最大maxval
-
maxw[u]表示u-f的最大w[i]
-
minw[u]表示u-f的最小w[i]
-
所以maxval=max(max(up[u],down[v]),maxw[v]-minw[u]);
-
现在问题就是如何快速的求出这四个变量,在这里我们可以对u,v的LCA(u,v)进行分类解决
-
对于LCA(u,v)是f的询问全部求出,然后再求LCA(u,v)是f的父亲的询问
-
这样当我们求LCA(u,v)是f的父亲的询问的时候就可以借用已经求出的LCA(u,v)是f的询问
-
的结果,这样就不用反复去求u->f的那四个变量值,u->father[f]也能快速求出
-
这个变化主要在寻找father[v]这个过程中进行,具体看代码
-
/*分析:先求出点u,v的最近公共祖先f,然后求u->f->v的利润最大值maxval 对于这个maxval可能有三种情况: 1:maxval是u->f的maxval 2:maxval是f->v的maxval 3:maxval是u->f的最小w[i]减去f->v的最大w[i] 分析到这很明显需要设置4个变量来求maxval: up[u]表示u->f的最大maxval down[u]表示f->u的最大maxval maxw[u]表示u-f的最大w[i] minw[u]表示u-f的最小w[i] 所以maxval=max(max(up[u],down[v]),maxw[v]-minw[u]); 现在问题就是如何快速的求出这四个变量,在这里我们可以对u,v的LCA(u,v)进行分类解决 对于LCA(u,v)是f的询问全部求出,然后再求LCA(u,v)是f的父亲的询问 这样当我们求LCA(u,v)是f的父亲的询问的时候就可以借用已经求出的LCA(u,v)是f的询问 的结果,这样就不用反复去求u->f的那四个变量值,u->father[f]也能快速求出 这个变化主要在寻找father[v]这个过程中进行,具体看代码 */ #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <queue> #include <algorithm> #include <map> #include <cmath> #include <iomanip> #define INF 99999999 typedef long long LL; using namespace std; const int MAX=50000+10; int n,m,size; int uu[MAX],vv[MAX],ww[MAX],sum[MAX]; int up[MAX],down[MAX],maxw[MAX],minw[MAX],father[MAX]; int head[MAX],head2[MAX],head3[MAX]; bool mark[MAX]; struct Edge{ int v,id,next; Edge(){} Edge(int V,int ID,int NEXT):v(V),id(ID),next(NEXT){} }edge[MAX*2],edge2[MAX*2],edge3[MAX*2]; void Init(int num){ for(int i=0;i<=num;++i)head[i]=head2[i]=head3[i]=-1,mark[i]=false; size=0; } void InsertEdge(int u,int v,int id){ edge[size]=Edge(v,id,head[u]); head[u]=size++; } void InsertEdge2(int u,int v,int id){ edge2[size]=Edge(v,id,head2[u]); head2[u]=size++; } void InsertEdge3(int u,int v,int id){ edge3[size]=Edge(v,id,head3[u]); head3[u]=size++; } int findset(int v){ if(v == father[v])return father[v]; int fa=father[v]; father[v]=findset(father[v]); up[v]=max(max(up[v],up[fa]),maxw[fa]-minw[v]); down[v]=max(max(down[v],down[fa]),maxw[v]-minw[fa]); maxw[v]=max(maxw[v],maxw[fa]); minw[v]=min(minw[v],minw[fa]); return father[v]; } void LCA(int u){ mark[u]=true; father[u]=u; for(int i=head2[u];i != -1;i=edge2[i].next){//对LCA(u,v)进行分类 int v=edge2[i].v,id=edge2[i].id; if(!mark[v])continue; int f=findset(v); InsertEdge3(f,v,id); } for(int i=head[u];i != -1;i=edge[i].next){ int v=edge[i].v; if(mark[v])continue; LCA(v); father[v]=u; } for(int i=head3[u];i != -1;i=edge3[i].next){ int id=edge3[i].id; findset(uu[id]); findset(vv[id]); sum[id]=max(max(up[uu[id]],down[vv[id]]),maxw[vv[id]]-minw[uu[id]]); } } int main(){ int u,v; while(~scanf("%d",&n)){ Init(n); for(int i=1;i<=n;++i){ scanf("%d",ww+i); up[i]=down[i]=0; maxw[i]=minw[i]=ww[i]; } for(int i=1;i<n;++i){ scanf("%d%d",&u,&v); InsertEdge(u,v,i); InsertEdge(v,u,i); } size=0; scanf("%d",&m); for(int i=0;i<m;++i){ scanf("%d%d",&uu[i],&vv[i]); InsertEdge2(uu[i],vv[i],i); InsertEdge2(vv[i],uu[i],i); } size=0; LCA(1); for(int i=0;i<m;++i)printf("%d ",sum[i]); } return 0; }
RMQ做法
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <queue> #include <algorithm> #include <map> #include <cmath> #include <iomanip> #define INF 99999999 typedef long long LL; using namespace std; const int MAX=50000+10; int n,m,size,top; int uu[MAX],vv[MAX],ww[MAX],anc[MAX]; int up[MAX][20],down[MAX][20],maxw[MAX][20],minw[MAX][20],deep[MAX]; int head[MAX],head2[MAX],bin[MAX],stack[MAX],mp[MAX][20],father[MAX]; bool mark[MAX]; struct Edge{ int v,id,next; Edge(){} Edge(int V,int ID,int NEXT):v(V),id(ID),next(NEXT){} }edge[MAX*2],edge2[MAX*2]; void Init(int num){ for(int i=0;i<=num;++i)head[i]=head2[i]=-1,mark[i]=false; size=top=0; } void InsertEdge(int u,int v,int id){ edge[size]=Edge(v,id,head[u]); head[u]=size++; } void InsertEdge2(int u,int v,int id){ edge2[size]=Edge(v,id,head2[u]); head2[u]=size++; } void dfs(int u,int father,int k){ deep[u]=k; for(int i=head[u];i != -1;i=edge[i].next){ int v=edge[i].v; if(v == father)continue; dfs(v,u,k+1); } } void RMQ(int u,int father){ stack[++top]=u; int fa=stack[top-1]; up[u][0]=down[u][0]=0; maxw[u][0]=minw[u][0]=ww[u]; for(int i=1;bin[i]<=top;++i){//2^i<=top fa=stack[top-bin[i-1]]; up[u][i]=max(max(up[u][i-1],up[fa][i-1]),maxw[fa][i-1]-minw[u][i-1]); down[u][i]=max(max(down[u][i-1],down[fa][i-1]),maxw[u][i-1]-minw[fa][i-1]); maxw[u][i]=max(maxw[u][i-1],maxw[fa][i-1]); minw[u][i]=min(minw[u][i-1],minw[fa][i-1]); mp[u][i]=stack[top-bin[i]]; } for(int i=head[u];i != -1;i=edge[i].next){ int v=edge[i].v; if(v == father)continue; RMQ(v,u); } --top; } int findset(int v){ if(v != father[v])father[v]=findset(father[v]); return father[v]; } void LCA(int u){ mark[u]=true; father[u]=u; for(int i=head2[u];i != -1;i=edge2[i].next){ int v=edge2[i].v,id=edge2[i].id; if(!mark[v])continue; anc[id]=findset(v); } for(int i=head[u];i != -1;i=edge[i].next){ int v=edge[i].v; if(mark[v])continue; LCA(v); father[v]=u; } } int search(int x){ int i=0; while(bin[i+1]<=x)++i; return i; } int Minw(int u,int anc){ int i=search(deep[u]-deep[anc]+1); if(bin[i] == deep[u]-deep[anc]+1)return minw[u][i]; return min(minw[u][i],Minw(mp[u][i],anc)); } int Maxw(int u,int anc){ int i=search(deep[u]-deep[anc]+1); if(bin[i] == deep[u]-deep[anc]+1)return maxw[u][i]; return max(maxw[u][i],Maxw(mp[u][i],anc)); } int Down(int u,int anc){ int i=search(deep[u]-deep[anc]+1); if(bin[i] == deep[u]-deep[anc]+1)return down[u][i]; int downfa=Down(mp[u][i],anc); downfa=max(downfa,down[u][i]); int minwfa=Minw(mp[u][i],anc); return max(downfa,maxw[u][i]-minwfa); } int UP(int u,int anc){ int i=search(deep[u]-deep[anc]+1); if(bin[i] == deep[u]-deep[anc]+1)return up[u][i]; int upfa=UP(mp[u][i],anc); upfa=max(upfa,up[u][i]); int maxwfa=Maxw(mp[u][i],anc); return max(upfa,maxwfa-minw[u][i]); } int main(){ bin[0]=1; for(int i=1;bin[i-1]<MAX;++i)bin[i]=bin[i-1]*2; int u,v; while(~scanf("%d",&n)){ Init(n); for(int i=1;i<=n;++i)scanf("%d",ww+i); for(int i=1;i<n;++i){ scanf("%d%d",&u,&v); InsertEdge(u,v,i); InsertEdge(v,u,i); } size=0; scanf("%d",&m); for(int i=0;i<m;++i){ scanf("%d%d",uu+i,vv+i); InsertEdge2(uu[i],vv[i],i); InsertEdge2(vv[i],uu[i],i); } dfs(1,-1,1); RMQ(1,-1); LCA(1); for(int i=0;i<m;++i){ int upmax=UP(uu[i],anc[i]),downmax=Down(vv[i],anc[i]); int Minww=Minw(uu[i],anc[i]),Maxww=Maxw(vv[i],anc[i]); printf("%d ",max(max(upmax,downmax),Maxww-Minww)); } } return 0; } /* 7 300 11 11 21 10 31 222 1 2 2 3 3 4 4 5 2 6 1 7 1 5 6 */