1. 程式人生 > >[樹剖]月下“毛景樹”

[樹剖]月下“毛景樹”

描述 毛毛蟲經過及時的變形,最終逃過的一劫,離開了菜媽的菜園。 毛毛蟲經過千山萬水,歷盡千辛萬苦,最後來到了小小的紹興一中的校園裡。

爬啊爬爬啊爬毛毛蟲爬到了一顆小小的“毛景樹”下面,發現樹上長著他最愛吃的毛毛果

“毛景樹”上有N個節點和N-1條樹枝,但節點上是沒有毛毛果的,毛毛果都是長在樹枝上的。但是這棵“毛景樹”有著神奇的魔力,他能改變樹枝上毛毛果的個 數:

Change k w:將第k條樹枝上毛毛果的個數改變為w個。

Cover u v w:將節點u與節點v之間的樹枝上毛毛果的個數都改變為w個。

Add u v w:將節點u與節點v之間的樹枝上毛毛果的個數都增加w個。

由於毛毛蟲很貪,於是他會有如下詢問:

Max u v:詢問節點u與節點v之間樹枝上毛毛果個數最多有多少個。

輸入 第一行一個正整數N。

接下來N-1行,每行三個正整數Ui,Vi和Wi,第i+1行描述第i條樹枝。

表示第i條樹枝連線節點Ui和節點Vi,樹枝上有Wi個毛毛果。 接下來是操作和詢問,以“Stop”結束。

輸出 對於毛毛蟲的每個詢問操作,輸出一個答案。

樣例輸入 4 1 2 8 1 3 7 3 4 9 Max 2 4 Cover 2 4 5 Add 1 4 10 Change 1 16 Max 2 4 Stop

樣例輸出 9 16

提示 【Data Range】 1<=N<=100,000,操作+詢問數目不超過100,000。 保證在任意時刻,所有樹枝上毛毛果的個數都不會超過10^9個。

吐槽: 做DP做成了個智障,來做下資料結構

分析: 樹剖板題,支援單點修改,區間修改,區間覆蓋,區間查詢即可

程式碼:(3.5K不多

#include<bits/stdc++.h>
#define ls tr[k].l
#define rs tr[k].r
#define mid (tr[k].l+tr[k].r>>1)
using namespace std;
const int N=100005;
int a[N],tot=0,head[N<<1],nxt[N<<1],vis[N<<1],pt[N],c[N<<1],siz[
N],dep[N],fa[N],top[N],hson[N],dfn[N],id[N],cnt=0; inline void add(int x,int y,int z){vis[++tot]=y,nxt[tot]=head[x];head[x]=tot,c[tot]=z;} void dfs1(int v){ int maxn=0;pt[v]=siz[v]=1; for(int i=head[v];i;i=nxt[i]){ int y=vis[i]; if(pt[y]) continue; a[y]=c[i]; fa[y]=v,dep[y]=dep[v]+1; dfs1(y); siz[v]+=siz[y]; if(siz[y]>maxn) {maxn=siz[y],hson[v]=y;} } } void dfs2(int v){ dfn[v]=++cnt,id[cnt]=v; if(!hson[v]) return; top[hson[v]]=top[v]; dfs2(hson[v]); for(int i=head[v];i;i=nxt[i]){ if(top[vis[i]]) continue; top[vis[i]]=vis[i]; dfs2(vis[i]); } } struct segtree{int l,r,maxx,add,cov;}tr[N<<2]; inline void pushcov(int k,int v) {tr[k].maxx=v,tr[k].cov=v,tr[k].add=0;} inline void pushadd(int k,int v) {tr[k].maxx+=v,tr[k].add+=v;} void pushdown(int k){ if(~tr[k].cov) pushcov(k<<1,tr[k].cov),pushcov(k<<1|1,tr[k].cov),tr[k].cov=-1; if(tr[k].add) pushadd(k<<1,tr[k].add),pushadd(k<<1|1,tr[k].add),tr[k].add=0; } void build(int k,int l,int r){ tr[k].l=l,tr[k].r=r,tr[k].cov=-1; if(l==r){tr[k].maxx=a[id[l]];return;} build(k<<1,l,mid),build(k<<1|1,mid+1,r); tr[k].maxx=max(tr[k<<1].maxx,tr[k<<1|1].maxx); } void update1(int k,int ql,int qr,int v){ //add if(ql>rs || qr<ls) return; if(ql<=ls && qr>=rs) return pushadd(k,v); pushdown(k); if(qr<=mid) update1(k<<1,ql,qr,v); else if(ql>mid) update1(k<<1|1,ql,qr,v); else update1(k<<1,ql,mid,v),update1(k<<1|1,mid+1,qr,v); tr[k].maxx=max(tr[k<<1].maxx,tr[k<<1|1].maxx); } void update2(int k,int ql,int qr,int v){ //cov if(ql>rs || qr<ls) return; if(ql<=ls && qr>=rs) return pushcov(k,v); pushdown(k); if(qr<=mid) update2(k<<1,ql,qr,v); else if(ql>mid) update2(k<<1|1,ql,qr,v); else update2(k<<1,ql,mid,v),update2(k<<1|1,mid+1,qr,v); tr[k].maxx=max(tr[k<<1].maxx,tr[k<<1|1].maxx); } int query(int k,int ql,int qr){ if(ql>rs || qr<ls) return 0; if(ql<=ls && qr>=rs) return tr[k].maxx; pushdown(k); if(qr<=mid) return query(k<<1,ql,qr); else if(ql>mid) return query(k<<1|1,ql,qr); return max(query(k<<1,ql,mid),query(k<<1|1,mid+1,qr)); } void change1(int x,int y,int v){ while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]]) swap(x,y); update1(1,dfn[top[x]],dfn[x],v),x=fa[top[x]]; } if(dep[x]<dep[y]) swap(x,y); update1(1,dfn[y]+1,dfn[x],v); } void change2(int x,int y,int v){ while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]]) swap(x,y); update2(1,dfn[top[x]],dfn[x],v),x=fa[top[x]]; } if(dep[x]<dep[y]) swap(x,y); update2(1,dfn[y]+1,dfn[x],v); } int ask(int x,int y){ int ans=0; while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]]) swap(x,y); ans=max(ans,query(1,dfn[top[x]],dfn[x])),x=fa[top[x]]; } if(dep[x]<dep[y]) swap(x,y); return max(ans,query(1,dfn[y]+1,dfn[x])); } int main(){ int n; cin>>n; for(int i=1;i<n;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); add(x,y,z);add(y,x,z); } dfs1(1),top[1]=1;dfs2(1);build(1,1,n); char op[10]; while(true){ scanf("%s",op); if(op[0]=='S') break; int x,y; scanf("%d%d",&x,&y); if(op[0]=='A') {int z;scanf("%d",&z);change1(x,y,z);} else if(op[0]=='M') printf("%d\n",ask(x,y)); else{ if(op[1]=='o') {int z;scanf("%d",&z);change2(x,y,z);} else{ int u=vis[x*2],v=vis[x*2-1]; if(dep[u]>dep[v])swap(u,v); update2 (1,dfn[v],dfn[v],y); } } } return 0; }