CodeForces - 396C On Changing Tree(树状数组)

Posted bztminamoto

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CodeForces - 396C On Changing Tree(树状数组)相关的知识,希望对你有一定的参考价值。

题目大意

给定一棵以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]=
;
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(树状数组)的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces 396C

CF396C On Changing Tree

Codeforces 869 C The Intriguing Obsession

Codeforces Round #439 (Div. 2) Problem C (Codeforces 869C) - 组合数学

C - The Intriguing Obsession /* Codeforces Round #439 */ (dp )

codeforces 620F. Xors on Segments