bzoj4034: [HAOI2015]T2

4034: [HAOI2015]T2

Time Limit: 10 Sec   Memory Limit: 256 MB
Submit: 921   Solved: 313
[ Submit][ Status][ Discuss]

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 。

//bzoj4034 单点更新和子树更新求区间
//操作 1 :把某个节点 x 的点权增加 a 。
//操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
//操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define inf -0x3f3f3f3f
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define mem0(a) memset(a,0,sizeof(a))
#define mem1(a) memset(a,-1,sizeof(a))
#define mem(a, b) memset(a, b, sizeof(a))
typedef long long ll;
const int maxn=101010;
int tot,p,v,L,R;
vector<int>G[maxn];
int siz[maxn],son[maxn],fa[maxn],deep[maxn],top[maxn],id[maxn],pre[maxn];
ll a[maxn];
ll addv[4*maxn];
ll sumv[4*maxn];

void init(int n){
    tot=0;
    for(int i=1;i<=n;i++)
        G[i].clear();
    mem0(addv);
    mem0(sumv);
    mem0(pre);
}

void dfs1(int u,int dep){
    deep[u]=dep;
    siz[u]=1,son[u]=0;
    for(int i=0;i<G[u].size();i++){
        int v=G[u][i];
        if(v==fa[u])
            continue;
        fa[v]=u;
        dfs1(v,dep+1);
        if(siz[son[u]]<siz[v]){
            son[u]=v;
        }
        siz[u]+=siz[v];
    }
}

void dfs2(int u,int tp){
    top[u]=tp;
    id[u]=++tot;
    pre[u]=id[u];
    if(son[u]!=0){  //这里要注意也要更新pre[u]啊,坑了一个小时
        dfs2(son[u],tp);
        pre[u]=max(pre[u],pre[son[u]]);
    }
    for(int i=0;i<G[u].size();i++){
        int v=G[u][i];
        if(son[u]==v||v==fa[u])
            continue;
        dfs2(v,v);
        pre[u]=max(pre[u],pre[v]);
    }
}

void pushup(int rt){
    sumv[rt]=sumv[rt<<1]+sumv[rt<<1|1];
}

void build(int l,int r,int rt){
    sumv[rt]=0;
    if(l==r)
        return ;
    int m=(l+r)>>1;
    build(lson);
    build(rson);
}

void pushdown(int rt,int l){
	if(addv[rt]!=0){
		addv[rt<<1]+=addv[rt];
		addv[rt<<1|1]+=addv[rt];
		sumv[rt<<1]+=addv[rt]*(l-(l>>1));
		sumv[rt<<1|1]+=addv[rt]*(l>>1);
		addv[rt]=0;
	}
}

void update1(int l,int r,int rt){
    if(l==r){
        sumv[rt]+=v;
        return ;
    }
    int m=(l+r)>>1;
    pushdown(rt,r-l+1);
    if(p<=m)
        update1(lson);
    else
        update1(rson);
    pushup(rt);
}

void update2(int l,int r,int rt){
    if(L<=l&&R>=r){
        addv[rt]+=v;
        sumv[rt]+=(ll)(r-l+1)*v;
        return ;
    }
    pushdown(rt,r-l+1);
    int m=(l+r)>>1;
    if(L<=m)
        update2(lson);
    if(R>m)
        update2(rson);
    pushup(rt);
}

ll query(int l,int r,int rt){
	ll ret=0;
	if(L<=l&&R>=r){
		return sumv[rt];
	}
	pushdown(rt,r-l+1);
	int m=(l+r)>>1;
	if(L<=m)
		ret+=query(lson);
	if(R>m)
		ret+=query(rson);
	return ret;
}

ll Query(int u,int v){
    ll ret=0;
    int f1=top[u],f2=top[v];
    while(f1!=f2){
        if(deep[f1]<deep[f2]){
            swap(f1,f2);
            swap(u,v);
        }
        L=id[f1],R=id[u];
        ret+=query(1,tot,1);
        u=fa[f1];
        f1=top[u];
    }
    if(deep[u]>deep[v]){
        swap(f1,f2);
        swap(u,v);
    }
    L=id[u],R=id[v];
    ret+=query(1,tot,1);
    return ret;
}

int main(){
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF){
        init(n);
        for(int i=1;i<=n;i++)
            scanf("%lld",&a[i]);
        int u;
        for(int i=1;i<n;i++){
            scanf("%d%d",&u,&v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        dfs1(1,0);
        dfs2(1,0);
        build(1,tot,1);
        for(int i=1;i<=n;i++){
            p=id[i],v=a[i];
            update1(1,tot,1);
        }
        int k;
        for(int i=1;i<=m;i++){
            scanf("%d",&k);
            if(k==1){
                scanf("%d%d",&u,&v);
                p=id[u];
                update1(1,tot,1);
            }
            if(k==2){
                scanf("%d%d",&u,&v);
                L=id[u],R=pre[u];
                update2(1,tot,1);
            }
            if(k==3){
                scanf("%d",&u);
                printf("%lld\n",Query(u,1));
            }
        }
    }
    return 0;
}


你可能感兴趣的:(bzoj4034: [HAOI2015]T2)