bzoj4034[HAOI2015]树上操作

大概树链剖分裸题吧(没开ll  WA了两发

4034: [HAOI2015]树上操作

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 6360  Solved: 2109
[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
#include <bits/stdc++.h>
#define N 100005
#define ll long long
using namespace std;
int son[N],num[N],dep[N],fa[N];
int cnt,p[N],fp[N],tp[N],a[N],n,m;
vector<int>vec[N];
int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f*x;
}
void dfs1(int v,int pre,int deep){
    num[v]=1;fa[v]=pre;dep[v]=deep+1;
    for(int i=0;i<vec[v].size();i++){
        if(vec[v][i]!=pre){
            dfs1(vec[v][i],v,deep+1);
            num[v]+=num[vec[v][i]];
            if(son[v]==-1||num[son[v]]<num[vec[v][i]]){
                son[v]=vec[v][i];
            }
        }
    }
}
void dfs2(int v,int td){
    p[v]=++cnt;fp[cnt]=v;tp[v]=td;
    if(son[v]!=-1) dfs2(son[v],td);
    for(int i=0;i<vec[v].size();i++){
        if(vec[v][i]!=fa[v]&&vec[v][i]!=son[v]) dfs2(vec[v][i],vec[v][i]);
    }
}
typedef struct node{
    int l,r;
    ll flag;
    ll sum;
}node;
node d[N<<2];
void update_add(int x,ll vul){
    d[x].flag+=vul;d[x].sum+=1ll*(d[x].r-d[x].l+1)*vul;
}
void push(int x){
    if(d[x].flag){
        update_add(x<<1,d[x].flag);
        update_add(x<<1|1,d[x].flag);
        d[x].flag=0;
    }
}
void up(int x){
    d[x].sum=d[x<<1].sum+d[x<<1|1].sum;
}
void built(int root,int l,int r){
    if(l==r){
        d[root].l=d[root].r=l;d[root].sum=a[fp[l]];d[root].flag=0;
        return ;
    }
    int mid=(l+r)>>1;
    built(root<<1,l,mid);
    built(root<<1|1,mid+1,r);
    d[root].l=d[root<<1].l;d[root].r=d[root<<1|1].r;d[root].flag=0;
    up(root);
}
void update(int root,int l,int r,int t){
    if(l<=d[root].l&&d[root].r<=r){
        update_add(root,t);
        return ;
    }
    push(root);
    int mid=(d[root].l+d[root].r)>>1;
    if(l<=mid) update(root<<1,l,r,t);
    if(r>mid) update(root<<1|1,l,r,t);
    up(root);
}
ll ans1;
void querty(int root,int l,int r){
    if(l<=d[root].l&&d[root].r<=r){
        ans1+=d[root].sum;
        return ;
    }
    int mid=(d[root].l+d[root].r)>>1;
    push(root);
    if(l<=mid) querty(root<<1,l,r);
    if(r>mid) querty(root<<1|1,l,r);
    up(root);
}
ll Sum(int v){
    ll ans=0;int vv=tp[v];
    while(tp[v]!=1){
        ans1=0;querty(1,p[vv],p[v]);
        ans+=ans1;
        v=fa[vv];vv=tp[v];
    }
    ans1=0;querty(1,1,p[v]);
    ans+=ans1;
    return ans;
}
int main(){
    ios::sync_with_stdio(false);
    n=read();m=read();cnt=0;
    for(int i=1;i<=n;i++) a[i]=read();
    for(int i=1;i<=n;i++) son[i]=-1;
    int t1,t2,op;
    for(int i=1;i<n;i++){
        t1=read();t2=read();
        vec[t1].push_back(t2);
        vec[t2].push_back(t1);
    }
    dfs1(1,0,0);
    dfs2(1,1);
    built(1,1,n);
    for(int i=1;i<=m;i++){
        op=read();
        if(op==1){
            t1=read();t2=read();
            update(1,p[t1],p[t1],t2);
        }
        else if(op==2){
            t1=read();t2=read();
            update(1,p[t1],p[t1]+num[t1]-1,t2);
        }
        else{
            t1=read();
            printf("%lld\n",Sum(t1));
        }
    }
    return 0;
}

 

 

posted @ 2018-01-31 19:18  wang9897  阅读(102)  评论(0编辑  收藏  举报