1. 程式人生 > >BZOJ 4034: [HAOI2015]樹上操作 樹鏈剖分 線段樹

BZOJ 4034: [HAOI2015]樹上操作 樹鏈剖分 線段樹

|| 線段 top www. img 復習 如果 ext hide

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

BZOJ 4034: [HAOI2015]樹上操作 樹鏈剖分 線段樹