1. 程式人生 > >CodeForces - 396C On Changing Tree(樹狀數組)

CodeForces - 396C On Changing Tree(樹狀數組)

amp 初始 發現 pac 維護 ORC else gin 樹狀

題目大意

給定一棵以1為根的樹,初始時所有點為0

給出樹的方式是從節點2開始給出每一個點的父親

然後是 $m$ 次操作,分為兩種

$1 v,k,x$ 表示在以v為根的子樹中的每一個點上添加 $x-i*k$( $i$ 表示節點與 $v$ 的距離)(包括點 $v$

$2 v$ 查詢節點 $v$ 的值

輸出每一個2操作的答案模 $1e9+7$ 的值

題解

話說真沒想到這題竟然這麽簡單……死活都想不出來……

先dfs預處理出每一個節點的dfs序,以及子樹代表的區間$ls$和$rs$,以及每一個點的深度$dep$

假設先$add(ls[v],x+dep[v]*k),add(rs[v]+1,-x-dep[v]*k)$,然後用樹狀數組維護前綴和,樹狀數組設為$c1$

可以發現,$v$這個點多加去了$dep[v]*k$,要減掉。同理可得,$v$的所有子樹都要減掉$dep[j]*k$($j$為$v$的子節點)

可以證明以上這麽亂搞之後每一個點的值都加上了正確的數

證:$j$節點經過這一操作後加上了$dep[v]*k-dep[j]*k=k*(dep[j]-dep[v])=k*dis[v,j]$

然後證明每一個節點都加上了正確的數值

那麽只要再開一個樹狀數組維護前綴$k$就可以了

查詢的答案就是$sum(ls[v],c1)-sum(ls[v],c2)*dep[v]$

 1 //minamoto
 2 #include<iostream>
 3
#include<cstdio> 4 #define ll long long 5 using namespace std; 6 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 7 char buf[1<<21],*p1=buf,*p2=buf; 8 inline int read(){ 9 #define num ch-‘0‘ 10 char ch;bool flag=0;int res;
11 while(!isdigit(ch=getc())) 12 (ch==-)&&(flag=true); 13 for(res=num;isdigit(ch=getc());res=res*10+num); 14 (flag)&&(res=-res); 15 #undef num 16 return res; 17 } 18 char sr[1<<21],z[20];int C=-1,Z; 19 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} 20 inline void print(ll x){ 21 if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x; 22 while(z[++Z]=x%10+48,x/=10); 23 while(sr[++C]=z[Z],--Z);sr[++C]=\n; 24 } 25 const int N=300005,mod=1e9+7; 26 int ver[N],head[N],Next[N],dep[N]; 27 int ls[N],rs[N]; 28 ll c[2][N]; 29 int n,tot,q,cnt; 30 inline void add(int x,ll val,int k){ 31 for(int i=x;i<=n;i+=i&(-i)) 32 (c[k][i]+=val)%=mod; 33 } 34 inline ll sum(int x){ 35 ll a=0,b=0; 36 for(int i=ls[x];i;i-=i&(-i)){ 37 a+=c[0][i],b+=c[1][i]; 38 } 39 return ((a-b*dep[x])%mod+mod)%mod; 40 } 41 void dfs(int u,int fa){ 42 ls[u]=++cnt; 43 dep[u]=dep[fa]+1; 44 for(int i=head[u];i;i=Next[i]) dfs(ver[i],u); 45 rs[u]=cnt; 46 } 47 int main(){ 48 //freopen("testdata.in","r",stdin); 49 n=read(); 50 for(int i=2;i<=n;++i){ 51 int fa=read(); 52 ver[++tot]=i,Next[tot]=head[fa],head[fa]=tot; 53 } 54 dfs(1,0); 55 q=read(); 56 while(q--){ 57 int opt=read(),v=read(); 58 if(opt&2) print(sum(v)); 59 else{ 60 ll x=read(),k=read(); 61 add(ls[v],x+dep[v]*k,0); 62 add(rs[v]+1,-x-dep[v]*k,0); 63 add(ls[v],k,1); 64 add(rs[v]+1,-k,1); 65 } 66 } 67 Ot(); 68 return 0; 69 }

CodeForces - 396C On Changing Tree(樹狀數組)