[BZOJ]4034: [HAOI2015]树上操作

[HAOI2015]树上操作

传送门

题目大意:三个操作 1:a,b,c b节点权值+c 2:a,b,c 以b为根的子树节点权值全部+c 3:a,b 查询b到根路径的权值和。

题解:树链剖分

操作1 ,2是区间修改,3是区间和。

看题解都提示开long long 了,我也开了,可是整形相乘赋值给Long long时爆了。

简直要哭晕了。

代码:

 

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 500005
#define LL long long
using namespace std;

int sumedge,cnt,n,m;
int head[maxn],size[maxn],dad[maxn],deep[maxn],top[maxn];
int tpos[maxn],re[maxn],w[maxn];

struct Tree{
    int l,r;LL sum,s;
}tr[maxn<<2];

struct Edge{
    int x,y,nxt;
    Edge(int x=0,int y=0,int nxt=0):
        x(x),y(y),nxt(nxt){}
}edge[maxn<<1];


void read(int &x){
    char ch=getchar();x=0;int f=1;
    for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
    x=x*f;
}

void add(int x,int y){
    edge[++sumedge]=Edge(x,y,head[x]);
    head[x]=sumedge;
}

void dfs(int x){
    size[x]=1;deep[x]=deep[dad[x]]+1;
    for(int i=head[x];i;i=edge[i].nxt){
        int v=edge[i].y;
        if(v==dad[x])continue;
        dad[v]=x;dfs(v);
        size[x]+=size[v];
    }
}

void dfs_(int x){
    int s=0;tpos[x]=++cnt;re[cnt]=x;
    if(!top[x])top[x]=x;
    for(int i=head[x];i;i=edge[i].nxt){
        int v=edge[i].y;
        if(v!=dad[x]&&size[v]>size[s])s=v;
    }
    if(s){
        top[s]=top[x];
        dfs_(s);
    }
    for(int i=head[x];i;i=edge[i].nxt){
        int v=edge[i].y;
        if(v!=dad[x]&&v!=s)dfs_(v);
    }
}

void pushup(int rt){
    tr[rt].sum=tr[rt<<1].sum+tr[rt<<1|1].sum;
    return;
}

void pushdown(int rt){
    if(!tr[rt].s)return;
    tr[rt<<1].s+=tr[rt].s;tr[rt<<1|1].s+=tr[rt].s;
    tr[rt<<1].sum+=(LL)(tr[rt<<1].r-tr[rt<<1].l+1)*tr[rt].s;
    tr[rt<<1|1].sum+=(LL)(tr[rt<<1|1].r-tr[rt<<1|1].l+1)*tr[rt].s;
    tr[rt].s=0;return;
}

void build(int rt,int l,int r){
    tr[rt].l=l;tr[rt].r=r;
    if(l==r){
        tr[rt].sum=w[re[l]];
        return;
    }
    int mid=(l+r)>>1;
    build(rt<<1,l,mid);build(rt<<1|1,mid+1,r);
    pushup(rt);
}

void change(int rt,int l,int r,int ql,int qr,int p){
    if(l>=ql&&r<=qr){
        tr[rt].sum+=(LL)(r-l+1)*p;
        tr[rt].s+=p;
        return;
    }
    pushdown(rt);
    int mid=(l+r)>>1;
    if(ql<=mid)change(rt<<1,l,mid,ql,qr,p);
    if(qr>mid)change(rt<<1|1,mid+1,r,ql,qr,p);
    pushup(rt);
}

LL query_sum(int rt,int l,int r,int ql,int qr){
    if(l>=ql&&r<=qr){
        return tr[rt].sum;
    }
    pushdown(rt);
    int mid=(l+r)>>1;LL ans=0;
    if(ql<=mid)ans+=query_sum(rt<<1,l,mid,ql,qr);
    if(qr>mid)ans+=query_sum(rt<<1|1,mid+1,r,ql,qr);
    return ans;
}

LL query(int x){
    LL ret=0;
    for(;top[x]!=1;){
        ret+=query_sum(1,1,n,tpos[top[x]],tpos[x]);
        x=dad[top[x]];
    }
    ret+=query_sum(1,1,n,1,tpos[x]);
    return ret;
}

int main(){
    read(n);read(m);
    for(int i=1;i<=n;i++)read(w[i]);
    for(int i=1;i<n;i++){
        int x,y;
        read(x);read(y);
        add(x,y);add(y,x);
    }
    dfs(1);dfs_(1);build(1,1,n);
    for(int i=1;i<=m;i++){
        int od,x,a;
        read(od);read(x);
        if(od==1){
            read(a);
            change(1,1,n,tpos[x],tpos[x],a);
        }else if(od==2){
            read(a);
            change(1,1,n,tpos[x],tpos[x]+size[x]-1,a);
        }else if(od==3){
            printf("%lld\n",query(x));
        }
    }
    return 0;
}
AC

 

posted @ 2017-10-20 17:37  ANhour  阅读(253)  评论(0编辑  收藏  举报