洛谷P3178[HAOI2015]樹上操作
阿新 • • 發佈:2018-12-31
題目描述
有一棵點數為 \(N\) 的樹,以點 \(1\) 為根,且樹點有邊權。然後有\(M\) 個操作,分為三種:
操作 \(1\) :把某個節點 \(x\) 的點權增加 \(a\) 。
操作 \(2\) :把某個節點 \(x\) 為根的子樹中所有點的點權都增加 \(a\)。
操作 \(3\) :詢問某個節點 \(x\) 到根的路徑中所有點的點權和。
輸入輸出格式
輸入格式:
第一行包含兩個整數 \(N\), \(M\) 。表示點數和運算元。
接下來一行 \(N\) 個整數,表示樹中節點的初始權值。
接下來 \(N-1\) 行每行兩個正整數 \(from\), \(to\) , 表示該樹中存在一條邊 (\(from\)
再接下來 \(M\) 行,每行分別表示一次操作。其中第一個數表示該操作的種類( \(1-3\) ) ,之後接這個操作的引數( \(x\) 或者 \(x\) \(a\) ) 。
輸出格式:
對於每個詢問操作,輸出該詢問的答案。答案之間用換行隔開。
輸入輸出樣例
輸入樣例#1:
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
輸出樣例#1:
6
9
13
說明
對於 \(100\%\) 的資料, \(N,M \leq 100000\),且所有輸入資料的絕對值都不會超過 \(10^6\) 。
思路:這道題跟洛谷\(P3384\)
程式碼:
#include<cstdio> #include<algorithm> #include<cctype> #define maxn 100007 #define ll long long #define ls rt<<1 #define rs rt<<1|1 using namespace std; int head[maxn],d[maxn],a[maxn]; int num,cnt,n,m,fa[maxn],id[maxn]; int w[maxn],top[maxn],size[maxn],son[maxn]; ll lazy[maxn<<2],sum[maxn<<2],y; inline ll qread() { char c=getchar();ll num=0,f=1; for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) num=num*10+c-'0'; return num*f; } struct node { int v,nxt; }e[maxn<<1]; inline void ct(int u, int v) { e[++num].v=v; e[num].nxt=head[u]; head[u]=num; } inline void pushup(int rt) { sum[rt]=sum[ls]+sum[rs]; } void build(int rt, int l, int r) { if(l==r) { sum[rt]=a[l]; return; } int mid=(l+r)>>1; build(ls,l,mid); build(rs,mid+1,r); pushup(rt); } inline void pushdown(int rt, int len) { if(lazy[rt]) { lazy[ls]+=lazy[rt]; lazy[rs]+=lazy[rt]; sum[ls]+=(len-(len>>1))*lazy[rt]; sum[rs]+=(len>>1)*lazy[rt]; lazy[rt]=0; } } void modify(int rt, int l, int r, int L, int R, ll val) { if(L>r||R<l) return; if(L<=l&&r<=R) { sum[rt]+=val*(r-l+1); lazy[rt]+=val; return; } int mid=(l+r)>>1; pushdown(rt,r-l+1); modify(ls,l,mid,L,R,val),modify(rs,mid+1,r,L,R,val); pushup(rt); } ll csum(int rt, int l, int r, int L, int R) { if(L>r||R<l) return 0; if(L<=l&&r<=R) return sum[rt]; int mid=(l+r)>>1; pushdown(rt,r-l+1); return csum(ls,l,mid,L,R)+csum(rs,mid+1,r,L,R); } void dfs1(int u, int f) { size[u]=1; for(int i=head[u];i;i=e[i].nxt) { int v=e[i].v; if(v!=f) { d[v]=d[u]+1; fa[v]=u; dfs1(v,u); size[u]+=size[v]; if(size[v]>size[son[u]]) son[u]=v; } } } void dfs2(int u, int t) { id[u]=++cnt; a[cnt]=w[u]; top[u]=t; if(son[u]) dfs2(son[u],t); for(int i=head[u];i;i=e[i].nxt) { int v=e[i].v; if(v!=fa[u]&&v!=son[u]) dfs2(v,v); } } ll calc(int x, int y) { ll ans=0; int fx=top[x],fy=top[y]; while(fx!=fy) { if(d[fx]<d[fy]) swap(x,y),swap(fx,fy); ans+=csum(1,1,cnt,id[fx],id[x]); x=fa[fx],fx=top[x]; } if(id[x]>id[y]) swap(x,y); ans+=csum(1,1,cnt,id[x],id[y]); return ans; } int main() { n=qread(),m=qread(); for(int i=1;i<=n;++i) w[i]=qread(); for(int i=1,u,v;i<n;++i) { u=qread(),v=qread(); ct(u,v);ct(v,u); } d[1]=1,fa[1]=1; dfs1(1,0);dfs2(1,1);build(1,1,n); for(int i=1,k,x;i<=m;++i) { k=qread(); if(k==1) { x=qread(),y=qread(); modify(1,1,n,id[x],id[x],y); } if(k==2) { x=qread(),y=qread(); modify(1,1,n,id[x],id[x]+size[x]-1,y); } if(k==3) { x=qread(); printf("%lld\n",calc(1,x)); } } return 0; }