BZOJ 4034: [HAOI2015]树上操作 树链剖分 线段树

http://www.lydsy.com/JudgeOnline/problem.php?id=4034

 
算是对线段树的一个复习,树链剖分+区间增减单点增减区间查询。真的简单到不用lca,但是线段树又写错了一次。
果然手熟才真的能码出来题,一段时间不写线段树操作都快忘完了,区间是放到标记上单点是直接放到值上这种东西都不记得。
如果haoi考这个,虽然简单但是我还真不一定能写出来,老年痴呆的边缘。。。
代码
  1 #include<iostream>  
  2 #include<cstdio>  
  3 #include<cstring>  
  4 #include<algorithm>  
  5 #include<cmath>  
  6 using namespace std;
  7 const int maxn=100100;
  8 const long long modn=1000000007;
  9 const long long minf=1<<30;
 10 int n,m;
 11 struct nod{
 12     int y,next;
 13 }e[maxn*2];
 14 int head[maxn]={},tot=0;
 15 int pos[maxn]={},fa[maxn]={},size[maxn]={},top[maxn]={},kid[maxn]={};
 16 long long road[maxn]={};
 17 long long a[maxn]={};
 18 struct seg{
 19     long long sum,w;
 20     int l,r;
 21     seg(){sum=w=0;l=r=0;}
 22 }t[maxn*4];
 23 void init(int x,int y){
 24     e[++tot].y=y;e[tot].next=head[x];
 25     head[x]=tot;
 26 }
 27 int dfs1(int x,int pa){
 28     int siz,hug=0,tsn=1,y;
 29     fa[x]=pa;
 30     for(int i=head[x];i;i=e[i].next){
 31         y=e[i].y;
 32         if(y==pa)continue;
 33         siz=dfs1(y,x);tsn+=siz;
 34         if(siz>hug)hug=siz,kid[x]=y;
 35     }size[x]=tsn;
 36     return tsn;
 37 }
 38 void dfs2(int x,int pa){
 39     int y;
 40     top[x]=pa;pos[x]=++tot;
 41     road[tot]=a[x];
 42     if(kid[x])dfs2(kid[x],pa);
 43     for(int i=head[x];i;i=e[i].next){
 44         y=e[i].y;
 45         if(y==kid[x]||y==fa[x])continue;
 46         dfs2(y,y);
 47     }
 48 }
 49 void pushup(int x){
 50     if(t[x].l<t[x].r)t[x].sum=t[x*2].sum+t[x*2+1].sum;
 51     t[x].sum+=t[x].w*(t[x].r-t[x].l+1);
 52 }
 53 void build(int x,int l,int r){
 54     t[x].l=l;t[x].r=r;
 55     if(l==r){t[x].sum=road[l];return;}
 56     int mid=(l+r)/2,ls=x*2,rs=x*2+1;
 57     build(ls,l,mid);
 58     build(rs,mid+1,r);
 59     pushup(x);
 60 }
 61 void add(int x,int l,int r,long long w){
 62     if(t[x].l>=l&&t[x].r<=r){
 63         if(t[x].l!=t[x].r){t[x].w+=w;pushup(x);}
 64         else t[x].sum+=w;
 65         return;
 66     }
 67     int mid=(t[x].l+t[x].r)/2,ls=x*2,rs=x*2+1;
 68     if(l<=mid)add(ls,l,r,w);
 69     if(r>mid)add(rs,l,r,w);
 70     pushup(x);
 71 }
 72 long long sum(int x,int l,int r,long long w){
 73     if(t[x].l>=l&&t[x].r<=r){
 74         return t[x].sum+w*(t[x].r-t[x].l+1);
 75     }
 76     int mid=(t[x].l+t[x].r)/2,ls=x*2,rs=x*2+1;long long tsn=0;
 77     if(l<=mid)tsn+=sum(ls,l,r,w+t[x].w);
 78     if(r>mid)tsn+=sum(rs,l,r,w+t[x].w);
 79     return tsn;
 80 }
 81 long long doit(int x){
 82     int y;long long tsn=0;
 83     for(y=top[x];y!=1;){
 84         tsn+=sum(1,pos[y],pos[x],0);
 85         x=fa[y];y=top[x];
 86     }
 87     tsn+=sum(1,pos[y],pos[x],0);
 88     return tsn;
 89 }
 90 int main(){
 91     scanf("%d%d",&n,&m);
 92     for(int i=1;i<=n;i++){
 93         scanf("%lld",&a[i]);
 94     }long long x,y,z;
 95     for(int i=1;i<n;i++){
 96         scanf("%lld%lld",&x,&y);
 97         init(x,y);init(y,x);
 98     }tot=0;dfs1(1,1);dfs2(1,1);
 99     build(1,1,n);
100     for(int i=1;i<=m;i++){
101         scanf("%lld",&z);
102         if(z==1){ scanf("%lld%lld",&x,&y);add(1,pos[x],pos[x],y); }
103         else if(z==2) { scanf("%d%lld",&x,&y);add(1,pos[x],pos[x]+size[x]-1,y); }
104         else {scanf("%lld",&x);printf("%lld\n",doit(x));}
105     }
106     return 0;
107 }
View Code

 

posted @ 2017-11-05 11:46  鲸头鹳  阅读(113)  评论(0编辑  收藏  举报