BZOJ 4034 :[HAOI2015]树上操作 树链剖分裸题

来源:互联网 发布:淘宝api 获取卖家订单 编辑:程序博客网 时间:2024/06/06 12:58

4034: [HAOI2015]树上操作

Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 4744 Solved: 1513
[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 。



这道题显然是一道树链剖分裸题,有一点值得注意,就是第二个操作的处理,其实我们可以发现,对于一棵子树的修改,我们可以发现,这棵子树中所有点的序号是连续的,所以我们可以记录一个该子树中序号最大的点,就可以进行操作了


#include<cstdio>#include<cstring>#include<iostream>#include<cmath>#include<algorithm>#include<vector>#include<map>#include<set>#define dnt long longconst int MAXN = 100000+10;using namespace std;int readin(){    int x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9')ch=getchar();    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}dnt val[MAXN];struct Line{    int from,to,nxt;}line[MAXN*2+10];int N,M,tail;int head[MAXN];int mx[MAXN],top[MAXN],dep[MAXN],siz[MAXN],son[MAXN],fa[MAXN],tid[MAXN],timer,rank[MAXN];dnt sum[MAXN*4+10],mark[MAXN*4+10];void add_line(int from,int to){    tail++;    line[tail].from=from;    line[tail].to=to;    line[tail].nxt=head[from];    head[from]=tail;}void dfs1(int u,int father,int d){    fa[u]=father;    dep[u]=d;    siz[u]=1;    for(register int i=head[u];i;i=line[i].nxt){        int v=line[i].to;        if(v!=father){            dfs1(v,u,d+1);            siz[u]+=siz[v];            if(son[u]==-1||siz[son[u]]<siz[v]) son[u]=v;        }    }}void dfs2(int u,int tp){    tid[u]=mx[u]=++timer;    rank[tid[u]]=u;    top[u]=tp;    if(son[u]==-1) return;    dfs2(son[u],tp);mx[u]=max(mx[u],mx[son[u]]);    for(register int i=head[u];i;i=line[i].nxt){        int v=line[i].to;        if(v!=son[u]&&v!=fa[u]){            dfs2(v,v);            mx[u]=max(mx[u],mx[v]);        }    }}void pushup(int rt){    sum[rt]=sum[rt<<1]+sum[rt<<1|1];}void pushdown(int rt,int len){    if(mark[rt]){        mark[rt<<1]+=mark[rt];        mark[rt<<1|1]+=mark[rt];        sum[rt<<1]+=(len-(len>>1))*mark[rt];        sum[rt<<1|1]+=(len>>1)*mark[rt];        mark[rt]=0;    }}void build(int l,int r,int rt){    mark[rt]=0;    if(l==r){        sum[rt]=val[rank[l]];        return;    }    int mid=(l+r)>>1;    build(l,mid,rt<<1);    build(mid+1,r,rt<<1|1);    pushup(rt);}void modify(int L,int R,dnt add,int l,int r,int rt){    if(L<=l&&R>=r){        mark[rt]+=add;        sum[rt]+=(r-l+1)*add;        return;    }    pushdown(rt,r-l+1);    int mid=(l+r)>>1;    if(L<=mid) modify(L,R,add,l,mid,rt<<1);    if(R>mid)  modify(L,R,add,mid+1,r,rt<<1|1);     pushup(rt);}dnt query(int L,int R,int l,int r,int rt){    if(L<=l&&R>=r){        return sum[rt];    }    pushdown(rt,r-l+1);    int mid=(l+r)>>1;    dnt sumn=0;    if(L<=mid) sumn+=query(L,R,l,mid,rt<<1);    if(R>mid)  sumn+=query(L,R,mid+1,r,rt<<1|1);    return sumn; }dnt _query(int from,int to){    dnt ans=0;    while(top[from]!=top[to]){        if(dep[top[from]]<dep[top[to]]) swap(from,to);        ans+=query(tid[top[from]],tid[from],1,N,1);        from=fa[top[from]];    }    if(dep[from]<dep[to]) swap(from,to);    ans+=query(tid[to],tid[from],1,N,1);    return ans;}int main(){    freopen("BZOJ4034.txt","r",stdin);    //freopen(".out","w",stdout);    int f,t;    memset(son,-1,sizeof(son));    scanf("%d%d",&N,&M);    for(register int i=1;i<=N;i++) scanf("%lld",&val[i]);    for(register int i=1;i<=N-1;i++){        scanf("%d%d",&f,&t);        add_line(f,t);        add_line(t,f);    }    dfs1(1,0,0);    dfs2(1,1);    build(1,N,1);    for(register int i=1;i<=M;i++){        int opt,te;        dnt mp;        scanf("%d",&opt);        if(opt==1){            scanf("%d%lld",&te,&mp);            modify(tid[te],tid[te],mp,1,N,1);        }else if(opt==2){            scanf("%d%lld",&te,&mp);            modify(tid[te],mx[te],mp,1,N,1);        }else{            scanf("%d",&te);            mp=_query(1,te);            printf("%lld\n",mp);        }    }    return 0;} 

这里写图片描述

原创粉丝点击