bzoj 4034 树上操作 树链剖分 解题报告

来源:互联网 发布:linux 用户安装anconda 编辑:程序博客网 时间:2024/06/07 01:42

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 。

思路

树链剖分。
线段树单点修改,标准修改;
修改子树的话,DFS序跑一次,修改就好了。
然后树链剖分,修改链。并不用LCA哦。。。

代码

#include<cmath>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int N=100000+5;int n,m,num,head[N],id,pos[N],maxn[N],v[N],bl[N],sized[N],fa[N];long long tag[4*N],sum[4*N];struct edge{    int v,next;}ed[2*N];void build(int u,int v){    ed[++num]=(edge){v,head[u]};head[u]=num;    ed[++num]=(edge){u,head[v]};head[v]=num;}void dfs(int x){    sized[x]=1;    for (int i=head[x];i;i=ed[i].next)    if (ed[i].v!=fa[x])    {        fa[ed[i].v]=x;        dfs(ed[i].v);        sized[x]+=sized[ed[i].v];        maxn[x]=max(maxn[x],maxn[ed[i].v]);     }}void dfs2(int x,int chain){    int k=0;    bl[x]=chain;pos[x]=maxn[x]=++id;    for (int i=head[i];i;i=ed[i].next)    if (ed[i].v!=fa[x]&&sized[ed[i].v]>sized[k]) k=ed[i].v;    if (k) {dfs2(k,chain);maxn[x]=max(maxn[x],maxn[k]);}    for (int i=head[i];i;i=ed[i].next)    if (ed[i].v!=fa[x]&&ed[i].v!=k)    {        dfs2(ed[i].v,ed[i].v);        maxn[x]=max(maxn[x],maxn[ed[i].v]);    }   }void pushdown(int lf,int rt,int k){    if (lf==rt) return ;    int mid=(lf+rt)/2;    long long t=tag[k];    tag[k]=0;    tag[k*2]+=t;    tag[k*2+1]+=t;    sum[k*2]+=t*(mid-lf+1);    sum[k*2+1]+=t*(rt-mid);}void add(int k,int lf,int rt,int x,int y,int val){    if (tag[k]!=0) pushdown(lf,rt,k);    if (lf==x&&y==rt) {tag[k]+=val;sum[k]+=(rt-lf+1)*val;return ;}    int mid=(lf+rt)/2;    if (x<=mid) add(k*2,lf,mid,x,min(mid,y),val);    if (y>=mid+1) add(k*2+1,mid+1,rt,max(mid+1,x),y,val);    sum[k]=sum[k*2]+sum[k*2+1];}long long query(int k,int lf,int rt,int x,int y){    long long ans=0;    if (tag[k]!=0) pushdown(lf,rt,k);    if (lf==x&&rt==y) return sum[k];    int mid=(lf+rt)/2;    if (x<=mid) ans+=query(k*2,lf,mid,x,min(mid,y));    if (y>=mid+1) ans+=query(k*2+1,mid+1,rt,max(mid+1,x),y);    return ans;}long long query(int x){    long long ans=0;    while(bl[x]!=1)    {        ans+=query(1,1,n,pos[bl[x]],pos[x]);        x=fa[bl[x]];    }    ans+=query(1,1,n,1,pos[x]);    return ans;}int main(){    int opt,x,a;    scanf("%d%d",&n,&m);    for (int i=1;i<=n;i++)    scanf("%d",&v[i]);    for (int i=1;i<n;i++)    {        int u,v;        scanf("%d%d",&u,&v);        build(u,v);    }    dfs(1);    dfs2(1,1);    for (int i=1;i<=n;i++)    add(1,1,n,pos[i],pos[i],v[i]);    while(m--)    {        scanf("%d%d",&opt,&x);        if (opt==1) {scanf("%d",&a);add(1,1,n,pos[x],pos[x],a);}        if (opt==2) {scanf("%d",&a);add(1,1,n,pos[x],maxn[x],a);}        if (opt==3) printf("%lld\n",query(x));    }    return 0;}
原创粉丝点击