【bzoj5421】奇怪的树 dfs序+线段树

Description

请你维护这样一棵树,它的每个结点上有一个权值,它支持两种操作:

1、Q x:询问以x结点为根的子树的所有结点的权值和;

2、C x y:将以x结点为根的子树的所有结点的权值加上y。

树的结点以1~n进行标号(n<=100000),初始时所有结点的权值为0。

Input

第一行有两个数字n,m。m表示询问的个数(m<=100000),n如题目所述。

接下来n-1行,每行两个整数x,y(1<=x,y<=n),表示x结点与y结点连接。

再接下来有m行,每行表示一个询问,询问格式如题目所述。

n,m<=500000,保证答案以及所有中间过程中的数值均在长整型范围内

Output

包含若干行,对应着每个询问的答案。

Sample Input

5 3
1 2
1 3
2 4
2 5
Q 1
C 1 4
Q 1

Sample Output

0
20

Sol

愉悦身心QAQ

学数学心态爆炸之后放松心情写的~

Code

#include <bits/stdc++.h>
#define mid ((s[x].l+s[x].r)>>1)
using namespace std;
int n,m,x,y,in[1000005],out[1000005],I;char op[5];vector<int>e[1000005];
void dfs(int x,int fa){in[x]=++I;for(int i=0;i<e[x].size();i++) if(e[x][i]!=fa) dfs(e[x][i],x);out[x]=I;}
struct seg{long long l,r,v,z;}s[10000005];
void down(int x)
{
    s[x*2].v+=s[x].z*(s[x*2].r-s[x*2].l+1);s[x*2+1].v+=(s[x].z*(s[x*2+1].r-s[x*2+1].l+1));
    s[x*2].z+=s[x].z;s[x*2+1].z+=s[x].z;s[x].z=0;
}
void build(int x,int L,int R){s[x]=(seg){L,R,0,0};if(L==R) return;build(x*2,L,mid),build(x*2+1,mid+1,R);}
long long query(int x,int L,int R)
{
    down(x);
    if(s[x].l>=L&&s[x].r<=R) return s[x].v;return (L<=mid?query(x*2,L,R):0)+(R>mid?query(x*2+1,L,R):0);
}
long long update(int x,int L,int R,long long V)
{
    down(x);
    if(s[x].l>=L&&s[x].r<=R) return s[x].v=s[x].v+(s[x].z=(s[x].z+V))*(s[x].r-s[x].l+1);
    return s[x].v=(L<=mid?update(x*2,L,R,V):s[x*2].v)+(R>mid?update(x*2+1,L,R,V):s[x*2+1].v);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++) scanf("%d%d",&x,&y),e[x].push_back(y),e[y].push_back(x);
    dfs(1,0);build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        scanf("%s",op);
        if(op[0]=='Q') scanf("%d",&x),printf("%lld\n",query(1,in[x],out[x]));
        if(op[0]=='C') scanf("%d%d",&x,&y),update(1,in[x],out[x],y);
    }
}

猜你喜欢

转载自www.cnblogs.com/CK6100LGEV2/p/9419816.html