1. 程式人生 > >HDU 5052 /// 樹鏈剖分+線段樹區間合併

HDU 5052 /// 樹鏈剖分+線段樹區間合併

題目大意:

給定n (表示樹有n個結點)

接下來n行給定n個點的點權(在這個點上買雞或者賣雞的價錢就是點權)

接下來n-1行每行給定 x y 表示x結點和y結點之間有一條邊

給定q (表示有q個詢問)

接下來q行 每行給定 x y v

查詢x到y的路徑上 先買雞再賣雞能夠贏得的最大利潤

買賣完後 x到y整條路徑的點權都要加上v

 

 

因為必須先買再賣 所以這個買賣有方向性

就得維護區間 從左向右買賣的最大利潤maxl 和 從右向左買賣的最大利潤maxr

而 從左向右買賣的利潤maxl = 右子區間的最大值 - 左子區間的最小值 (maxr同理)

所以還要維護區間 最大值maxw 和 最小值minw

整條路徑都加上v 區間更新還要加個 lazy 標記

 

查詢時 最後路徑被分成 LCA-x 和 LCA-y 由LCA到底部的兩段 

所以按方向更新答案應該 ans=max( LCA-y.maxl , LCA-x.maxr )

最後還要通過 ans=max( ans , LCA-y.maxw - LCA-x.minw ) 更新一下答案

 

最後 我的程式碼裡 線段樹的 pushUp() 操作直接呼叫了 Merge() 函式

而 lazy 在合併前已經更新過了 防止出錯 將已得到的 lazy 傳參賦值

而查詢時的合併操作 只需要查詢線段樹 不需要修改 所以lazy直接傳個沒用的0就好了

 

#include <stdio.h>
#include <algorithm>
#include <cstring>
using namespace std;
#define INF 0x3f3f3f3f
#define mem(i,j) memset(i,j,sizeof(i))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define root 1,n,1

const int maxn=1e5+5;
int n, q, w[maxn];

struct IntervalTree { struct EDGE { int to,ne; }e[maxn<<1]; int head[maxn], tot; void addE(int u,int v) { e[tot].to=v; e[tot].ne=head[u]; head[u]=tot++; } int fa[maxn], son[maxn], dep[maxn], num[maxn]; int top[maxn], p[maxn], fp[maxn], pos; void init() { tot=1; mem(head,0); pos=0; mem(son,0); } struct TREE { int lazy; int maxw,minw; // 區間極值 int maxl,maxr; // 從左開始最大差值 從右開始最大差值 TREE(){ lazy=maxw=minw=maxl=maxr=0; } }tree[maxn<<2]; // --------------------以下是線段樹------------------------- TREE Merge(TREE L,TREE R,int lazy) { if(R.maxw==0) return L; TREE ans; ans.lazy=lazy; ans.maxw=max(L.maxw,R.maxw); ans.minw=min(L.minw,R.minw); ans.maxl=max(max(L.maxl,R.maxl),R.maxw-L.minw); ans.maxr=max(max(L.maxr,R.maxr),L.maxw-R.minw); return ans; } void pushUp(int rt) { tree[rt]=Merge(tree[rt<<1],tree[rt<<1|1],tree[rt].lazy); } void pushDown(int rt) { if(tree[rt].lazy) { int t=tree[rt].lazy; tree[rt<<1].minw+=t; tree[rt<<1].maxw+=t; tree[rt<<1].lazy+=t; tree[rt<<1|1].minw+=t; tree[rt<<1|1].maxw+=t; tree[rt<<1|1].lazy+=t; tree[rt].lazy=0; } // 差值不變 不需要更新 } void build(int l,int r,int rt) { tree[rt].lazy=0; if(l==r) { tree[rt].maxw=tree[rt].minw=fp[l]; tree[rt].maxl=tree[rt].maxr=0; return; } int m=(l+r)>>1; build(lson), build(rson); pushUp(rt); } void update(int L,int R,int v,int l,int r,int rt) { if(l==L && R==r) { tree[rt].lazy+=v; tree[rt].maxw+=v; tree[rt].minw+=v; return; } pushDown(rt); int m=(l+r)>>1; if(R<=m) update(L,R,v,lson); else if(L>m) update(L,R,v,rson); else update(L,m,v,lson),update(m+1,R,v,rson); pushUp(rt); } TREE query(int L,int R,int l,int r,int rt) { if(L==l && r==R) return tree[rt]; pushDown(rt); int m=(l+r)>>1; if(R<=m) return query(L,R,lson); else if(L>m) return query(L,R,rson); else return Merge(query(L,m,lson),query(m+1,R,rson),tree[rt].lazy); } // --------------------以上是線段樹------------------------- // --------------------以下是樹鏈剖分------------------------- void dfs1(int u,int pre,int d) { dep[u]=d; fa[u]=pre; num[u]=1; for(int i=head[u];i;i=e[i].ne) { int v=e[i].to; if(v!=fa[u]) { dfs1(v,u,d+1); num[u]+=num[v]; if(!son[u] || num[v]>num[son[u]]) son[u]=v; } } } void dfs2(int u,int sp) { top[u]=sp; p[u]=++pos; fp[p[u]]=w[u]; if(!son[u]) return; dfs2(son[u],sp); for(int i=head[u];i;i=e[i].ne) { int v=e[i].to; if(v!=son[u] && v!=fa[u]) dfs2(v,v); } } int solve(int x,int y,int v) { int fx=top[x], fy=top[y]; TREE ans1, ans2; while(fx!=fy) { if(dep[fx]>dep[fy]) { ans1=Merge(query(p[fx],p[x],root),ans1,0); update(p[fx],p[x],v,root); x=fa[fx]; } else { ans2=Merge(query(p[fy],p[y],root),ans2,0); update(p[fy],p[y],v,root); y=fa[fy]; } fx=top[x], fy=top[y]; } if(p[x]>p[y]) { ans1=Merge(query(p[y],p[x],root),ans1,0); update(p[y],p[x],v,root); } else { ans2=Merge(query(p[x],p[y],root),ans2,0); update(p[x],p[y],v,root); } int ans=max(ans1.maxr,ans2.maxl); if(ans1.minw) ans=max(ans,ans2.maxw-ans1.minw); return ans; } // --------------------以上是樹鏈剖分------------------------- void initQTree() { dfs1(1,0,0), dfs2(1,1); build(root); } }T; int main() { int t; scanf("%d",&t); while(t--) { scanf("%d",&n); T.init(); for(int i=1;i<=n;i++) scanf("%d",&w[i]); for(int i=2;i<=n;i++) { int u,v; scanf("%d%d",&u,&v); T.addE(u,v); T.addE(v,u); } T.initQTree(); scanf("%d",&q); while(q--) { int x,y,v; scanf("%d%d%d",&x,&y,&v); printf("%d\n",T.solve(x,y,v)); } } return 0; }
View Code