1. 程式人生 > >bzoj 4034: [HAOI2015]樹上操作——樹鏈剖分

bzoj 4034: [HAOI2015]樹上操作——樹鏈剖分

技術 ins 最大的 輸出 urn 第一個 nbsp void 三種

Description

有一棵點數為 N 的樹,以點 1 為根,且樹點有邊權。然後有 M 個 操作,分為三種: 操作 1 :把某個節點 x 的點權增加 a 。 操作 2 :把某個節點 x 為根的子樹中所有點的點權都增加 a 。 操作 3 :詢問某個節點 x 到根的路徑中所有點的點權和。

Input

第一行包含兩個整數 N, M 。表示點數和操作數。接下來一行 N 個整數,表示樹中節點的初始權值。接下來 N-1 行每行三個正整數 fr, to , 表示該樹中存在一條邊 (fr, to) 。再接下來 M 行,每行分別表示一次操作。其中 第一個數表示該操作的種類( 1-3 ) ,之後接這個操作的參數( x 或者 x a ) 。

Output

對於每個詢問操作,輸出該詢問的答案。答案之間用換行隔開。

Sample Input

5 5
1 2 3 4 5
1 2
1 4
2 3
2 5
3 3
1 2 1
3 5
2 1 2
3 3

Sample Output

6
9
13

HINT

對於 100% 的數據, N,M<=100000 ,且所有輸入數據的絕對值都不會超過 10^6 。

—————————————————————————————

這道題其實也是裸題QAQ 子樹求和就是求個子樹內id最大的點 從根到這個點的編號剛好包含了整個子樹

技術分享
#include<cstdio>
#include<cstring>
#include
<algorithm> #define LL long long const int M=150007; int read(){ int ans=0,f=1,c=getchar(); while(c<0||c>9){if(c==-) f=-1; c=getchar();} while(c>=0&&c<=9){ans=ans*10+(c-0); c=getchar();} return ans*f; } int max(int x,int y){return x>y?x:y;} int n,m; int
first[M],cnt=1; struct node{int to,next;}e[2*M]; void ins(int a,int b){e[++cnt]=(node){b,first[a]}; first[a]=cnt;} void insert(int a,int b){ins(a,b); ins(b,a);} int top[M],sz[M],son[M],mx[M],fa[M],id[M],idp=1; void f1(int x){ sz[x]=1; for(int i=first[x];i;i=e[i].next){ int now=e[i].to; if(now==fa[x]) continue; fa[now]=x; f1(now); sz[x]+=sz[now]; if(sz[now]>sz[son[x]]) son[x]=now; } } void f2(int x,int tp){ top[x]=tp; mx[x]=id[x]=idp++; if(son[x]) f2(son[x],tp),mx[x]=max(mx[x],mx[son[x]]); for(int i=first[x];i;i=e[i].next){ int now=e[i].to; if(now!=fa[x]&&now!=son[x]) f2(now,now),mx[x]=max(mx[x],mx[now]); } } struct pos{int l,r; LL sum,tag;}tr[4*M]; void build(int x,int l,int r){ tr[x].l=l; tr[x].r=r; if(l==r) return ; int mid=(l+r)>>1; build(x<<1,l,mid); build(x<<1^1,mid+1,r); } void up(int x){tr[x].sum=tr[x<<1].sum+tr[x<<1^1].sum;} void down(int x){ if(tr[x].tag){ int ls=x<<1,rs=x<<1^1; LL v=tr[x].tag; tr[x].tag=0; tr[ls].tag+=v; tr[rs].tag+=v; tr[ls].sum+=1LL*(tr[ls].r-tr[ls].l+1)*v; tr[rs].sum+=1LL*(tr[rs].r-tr[rs].l+1)*v; } } void modify(int x,int L,int R,LL s){ if(L<=tr[x].l&&tr[x].r<=R){tr[x].tag+=s; tr[x].sum+=(tr[x].r-tr[x].l+1)*s; return ;} down(x); int mid=(tr[x].l+tr[x].r)>>1; if(L<=mid) modify(x<<1,L,R,s); if(R>mid) modify(x<<1^1,L,R,s); up(x); } LL v[M]; LL push_sum(int x,int L,int R){ if(L<=tr[x].l&&tr[x].r<=R) return tr[x].sum; down(x); int mid=(tr[x].l+tr[x].r)>>1; LL ans=0; if(L<=mid) ans+=push_sum(x<<1,L,R); if(R>mid) ans+=push_sum(x<<1^1,L,R); return ans; } LL qsum(int x){ LL sum=0; while(top[x]!=top[1]){ sum+=push_sum(1,id[top[x]],id[x]); x=fa[top[x]]; } sum+=push_sum(1,id[1],id[x]); return sum; } int main(){ int k,x,y; n=read(); m=read(); for(int i=1;i<=n;i++) v[i]=read(); for(int i=1;i<n;i++) x=read(),y=read(),insert(x,y); build(1,1,n); f1(1); f2(1,1); for(int i=1;i<=n;i++) modify(1,id[i],id[i],v[i]); for(int i=1;i<=m;i++){ k=read(); if(k==1) x=read(),y=read(),modify(1,id[x],id[x],y); else if(k==2) x=read(),y=read(),modify(1,id[x],mx[x],y); else x=read(),printf("%lld\n",qsum(x)); } return 0; }
View Code

bzoj 4034: [HAOI2015]樹上操作——樹鏈剖分