BZOJ4034 [HAOI2015]树上操作

来源:互联网 发布:进口商品数据 编辑:程序博客网 时间:2024/05/16 11:30

标签:树链剖分,线段树

题目

题目传送门

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的时候记录每棵子树最右边那个节点的值,存放在mx数组内,因为我们dfs任意一个子树的区间[l,r]在线段树上都是连续的

打上lazy标记的线段树

注意有些值要开long long

code

#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<cstring>#include<algorithm>#define rep(i,a,b) for(int i=a;i<=b;i++)#define dep(i,a,b) for(int i=a;i>=b;i--)#define ll long long#define mem(x,num) memset(x,num,sizeof x)#define reg(x) for(int i=last[x];i;i=e[i].next)using namespace std;inline ll read(){    ll f=1,x=0;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}const int maxn=1e5+6;int n,m,cnt=0,last[maxn],sz=0;int pos[maxn],mx[maxn],v[maxn],belong[maxn],fa[maxn],son[maxn];ll tag[maxn<<2],sum[maxn<<2];struct edge{int to,next;}e[maxn<<1];void insert(int u,int v){    e[++cnt]=(edge){v,last[u]};last[u]=cnt;    e[++cnt]=(edge){u,last[v]};last[v]=cnt;}void dfs1(int x){    son[x]=1;    reg(x){        if(e[i].to==fa[x])continue;        fa[e[i].to]=x;        dfs1(e[i].to);        son[x]+=son[e[i].to];        mx[x]=max(mx[x],mx[e[i].to]);    }}void dfs2(int x,int chain){    pos[x]=mx[x]=++sz;belong[x]=chain;int k=0;    reg(x)if(e[i].to!=fa[x]&&son[e[i].to]>son[k])k=e[i].to;    if(!k)return;dfs2(k,chain);mx[x]=max(mx[x],mx[k]);    reg(x)if(e[i].to!=fa[x]&&e[i].to!=k)dfs2(e[i].to,e[i].to),mx[x]=max(mx[x],mx[e[i].to]);}void pushdown(int l,int r,int k){    if(l==r)return;    int mid=(l+r)>>1;ll t=tag[k];tag[k]=0;    tag[k<<1]+=t;tag[k<<1|1]+=t;    sum[k<<1]+=t*(mid-l+1);    sum[k<<1|1]+=t*(r-mid);}void change(int k,int l,int r,int x,int y,ll val){    if(tag[k])pushdown(l,r,k);    if(l==x&&y==r){tag[k]+=val;sum[k]+=(r-l+1)*val;return;}    int mid=(l+r)>>1;    if(x<=mid)change(k<<1,l,mid,x,min(mid,y),val);    if(y>=mid+1)change(k<<1|1,mid+1,r,max(mid+1,x),y,val);    sum[k]=sum[k<<1]+sum[k<<1|1];}ll querysum(int k,int l,int r,int x,int y){    if(tag[k])pushdown(l,r,k);    if(l==x&&y==r)return sum[k];    int mid=(l+r)>>1;ll ans=0;    if(x<=mid)ans+=querysum(k<<1,l,mid,x,min(mid,y));    if(y>=mid+1)ans+=querysum(k<<1|1,mid+1,r,max(mid+1,x),y);    return ans;}ll query(int x){    ll ans=0;    while(belong[x]!=1){        ans+=querysum(1,1,n,pos[belong[x]],pos[x]);        x=fa[belong[x]];    }    ans+=querysum(1,1,n,1,pos[x]);    return ans;}int main(){    n=read(),m=read();    rep(i,1,n)v[i]=read();    rep(i,1,n-1){        int u=read(),v=read();        insert(u,v);    }    dfs1(1);dfs2(1,1);    rep(i,1,n)change(1,1,n,pos[i],pos[i],v[i]);    rep(i,1,m){        int opt=read();        if(opt==1){            int x=read(),y=read();            change(1,1,n,pos[x],pos[x],y);        }        if(opt==2){            int x=read(),y=read();            change(1,1,n,pos[x],mx[x],y);        }        if(opt==3){            int x=read();            printf("%lld\n",query(x));        }    }    return 0;}
阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 全自动制香机多少钱一台 制香机械厂家 制包厂 制箱厂 制香业 制砂厂 如何制香 制香技术 制香加工 制香粉碎机 制香的机器 全自动制香机器价格 制香机子 制香机器图片 办制香厂 制香厂怎么跑销售 开个制香厂 开香厂 吕氏制香厂 小制香厂 小冈制香厂 香厂 开个制香厂需要多少钱 生产佛香的厂家 创办制香厂创业全指南 制香机器价格 制香设备厂 全自动制香机械 制香生产设备 制香机械价格 自动制香机多少钱 半自动制香机价格 微型制香机 制香机怎么样 小型制香机价格 湘香缘制香机可靠吗 家用制香机 华延制香机 那里有制香机 制香机厂家 制香机的价格