hdu 5052 Yaoge’s maximum profit
有n个节点的树,有q次操作,每次操作选择一条路径问从起点出发到终点可以在任意点花vi买入一个商品并在之后任意一点以vj卖掉。
问最大收益是多少,并在每次操作后将那条路径所有点权加上v。
树链剖分将问题变为直线上的问题后,考虑用线段树维护一个最大值与最小值,以及从直线左到右的最大收益以及直线右到左的最大收益。
在区间合并时,最大收益可能时两个子区间最大收益的max,也可能是左区间的最小值与右区间最大值的差值。
pushdown的时候只需要把最大值最小值+v即可,因为都加上v对收益没有影响。
最后查询的时候线段树合并即可,注意左右两条链还可能产生差值影响答案。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> #define Lson l,mid,rt<<1 #define Rson mid+1,r,rt<<1|1 using namespace std; const int M = 1e5+7; int _,n,q,a[M]; int head[M],cnt,tot,tmp; int sz[M],f[M],son[M],dep[M],rnk[M],id[M],top[M]; struct edge { int v,next; }e[M<<1]; struct Tree{ int mx,mn,rpro,lpro; int lazy; }tree[M<<3]; void init(){ tot=cnt=0;memset(head,-1,sizeof(head)); } /**************************找重儿子****************************/ void add(int u,int v){ e[++cnt].v=v;e[cnt].next=head[u]; head[u]=cnt; } void dfs(int u,int fa,int d){ sz[u]=1,son[u]=-1,f[u]=fa,dep[u]=d; for(int i=head[u];~i;i=e[i].next){ int v=e[i].v; if(v==fa) continue; dfs(v,u,d+1); sz[u]+=sz[v]; if(son[u]==-1||sz[v]>sz[son[u]]) son[u]=v; } return ; } void dfs1(int u,int t){ id[u]=++tot; rnk[tot]=u; top[u]=t; if(son[u]==-1) return; dfs1(son[u],t); for(int i=head[u];~i;i=e[i].next){ int v=e[i].v; if(v==f[u]||v==son[u]) continue; dfs1(v,v); } return ; } /**************************线段树****************************/ void Pushup(int rt,int l,int r){ tree[rt].mn=min(tree[l].mn,tree[r].mn); tree[rt].mx=max(tree[l].mx,tree[r].mx); tree[rt].rpro=max(tree[l].rpro,tree[r].rpro);//从左到右的最大收益 tree[rt].lpro=max(tree[l].lpro,tree[r].lpro);//从右到左 if(tree[l].mn<tree[r].mx){ tree[rt].rpro=max(tree[rt].rpro,tree[r].mx-tree[l].mn); } if(tree[l].mx>tree[r].mn){ tree[rt].lpro=max(tree[rt].lpro,tree[l].mx-tree[r].mn); } } void Pushdown(int rt,int l,int r){ if(tree[rt].lazy){//区间都+v对收益没影响 int v=tree[rt].lazy; tree[rt].lazy=0; tree[l].lazy+=v; tree[r].lazy+=v; tree[l].mx+=v;tree[l].mn+=v; tree[r].mx+=v;tree[r].mn+=v;//把mx写成了mn调了半个小时shit } } void build(int l,int r,int rt){ tree[rt].lazy=0; if(l==r){ //cout<<l<<" gg "<<rnk[l]<<" rt"<<rt<<endl; tree[rt].mn=tree[rt].mx=a[rnk[l]]; tree[rt].rpro=tree[rt].lpro=0; return ; } int mid=(l+r)>>1; build(Lson); build(Rson); Pushup(rt,rt<<1,rt<<1|1); //cout<<l<<" "<<r<<" "<<tree[rt].lpro<<" "<<tree[rt].rpro<<" "<<tree[rt].mx<<" "<<tree[rt].mn<<endl; } void update(int L,int R,int l,int r,int rt,int v){ if(L<=l&&r<=R){ tree[rt].lazy+=v; tree[rt].mx+=v;tree[rt].mn+=v; return ; } Pushdown(rt,rt<<1,rt<<1|1); int mid=(l+r)>>1; if(L<=mid) update(L,R,Lson,v); if(R>mid) update(L,R,Rson,v); Pushup(rt,rt<<1,rt<<1|1); //cout<<l<<" "<<r<<" "<<tree[rt].lpro<<" "<<tree[rt].rpro<<" "<<tree[rt].mx<<" "<<tree[rt].mn<<endl; } int query(int L,int R,int l,int r,int rt){ if(L==l&&R==r){ return rt; } Pushdown(rt,rt<<1,rt<<1|1); int mid=(l+r)>>1,res; if(L>mid){ res=query(L,R,Rson); //Pushup(rt,rt<<1,rt<<1|1); return res; } else if(R<=mid){ res=query(L,R,Lson); //Pushup(rt,rt<<1,rt<<1|1); return res; } else{ int ll=query(L,mid,Lson),rr=query(mid+1,R,Rson); Pushup(++tmp,ll,rr); return tmp; } } /**************************剖分****************************/ void updates(int x,int y,int v){ int fx=top[x],fy=top[y]; while(fx!=fy){ if(dep[fx]>dep[fy]){ update(id[fx],id[x],1,n,1,v); x=f[fx],fx=top[x]; } else{ update(id[fy],id[y],1,n,1,v); y=f[fy],fy=top[y]; } } if(dep[x]<dep[y]) update(id[x],id[y],1,n,1,v); else update(id[y],id[x],1,n,1,v); } int sum(int x,int y){ //cout<<"1:"<<tree[8].mn<<" "<<tree[8].mx<<endl; int fx=top[x],fy=top[y]; int xl,xr=-1,yl,yr=-1;tmp=M<<2; while(fx!=fy){ if(dep[fx]>dep[fy]){ xl=query(id[fx],id[x],1,n,1); if(xr==-1) xr=xl; else{ Pushup(++tmp,xl,xr);xr=tmp; } x=f[fx],fx=top[x]; } else{ yl=query(id[fy],id[y],1,n,1); if(yr==-1) yr=yl; else{ Pushup(++tmp,yl,yr);yr=tmp; } y=f[fy],fy=top[y]; } } if(dep[x]<dep[y]){ yl=query(id[x],id[y],1,n,1); if(yr==-1) yr=yl; else{ Pushup(++tmp,yl,yr);yr=tmp; } } else{ xl=query(id[y],id[x],1,n,1); if(xr==-1) xr=xl; else{ Pushup(++tmp,xl,xr);xr=tmp; } } //cout<<"xr:"<<xr<<endl; if(yr==-1) return tree[xr].lpro; if(xr==-1) return tree[yr].rpro; int res; res=max(tree[xr].lpro,tree[yr].rpro);//左右两条链的答案 if(tree[xr].mn<tree[yr].mx){//左右两条链还有可能产生答案 res=max(res,tree[yr].mx-tree[xr].mn); } return res; } int main(){ scanf("%d",&_); while(_--){ init(); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<n;i++){ int from,to; scanf("%d%d",&from,&to); add(from,to);add(to,from); } dfs(1,-1,1);dfs1(1,1); build(1,n,1); scanf("%d",&q); while(q--){ int from,to,v; scanf("%d%d%d",&from,&to,&v); printf("%d\n",sum(from,to)); updates(from,to,v); } } return 0; }