1. 程式人生 > >BZOJ4034: [HAOI2015]樹上操作

BZOJ4034: [HAOI2015]樹上操作

mil top space ring ble lib esp 樹鏈剖分 AI

【傳送門:BZOJ4034】


簡要題意:

  給出一棵有n個有權節點的樹且根節點為1,有m個操作,3種操作:

  1 x a將x點的權值增加a

  2 x a將x的子樹的所有節點增加a

  3 x求出x到根節點的路徑上的所有點的權值和


題解:

  裸樹鏈剖分,只要在處理輕重鏈的時候記錄x子樹的最小的編號和最大的編號即可

  註意加long long


參考代碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include
<cstdlib> using namespace std; typedef long long LL; struct node { int x,y,next; }a[210000];int len,last[110000]; void ins(int x,int y) { len++; a[len].x=x;a[len].y=y; a[len].next=last[x];last[x]=len; } int tot[110000],dep[110000],fa[110000],son[110000]; void pre_tree_node(int x) { tot[x]
=1;son[x]=0; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=fa[x]) { fa[y]=x; dep[y]=dep[x]+1; pre_tree_node(y); tot[x]+=tot[y]; if(tot[y]>tot[son[x]]) son[x]=y; } } } int top[110000
],ys[110000],z,L[110000],R[110000]; void pre_tree_edge(int x,int tp) { ys[x]=++z;top[x]=tp; L[x]=z; if(son[x]!=0) pre_tree_edge(son[x],tp); for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=fa[x]&&y!=son[x]) pre_tree_edge(y,y); } R[x]=z; } struct trnode { int l,r,lc,rc;LL c,lazy; }tr[210000];int trlen; LL s[110000]; void bt(int l,int r) { trlen++;int now=trlen; tr[now].l=l;tr[now].r=r;tr[now].c=tr[now].lazy=0; tr[now].lc=tr[now].rc=-1; if(l<r) { int mid=(l+r)/2; tr[now].lc=trlen+1;bt(l,mid); tr[now].rc=trlen+1;bt(mid+1,r); } } void update(int now) { int lc=tr[now].lc,rc=tr[now].rc; if(lc!=-1) tr[lc].c+=LL(tr[lc].r-tr[lc].l+1)*tr[now].lazy,tr[lc].lazy+=tr[now].lazy; if(rc!=-1) tr[rc].c+=LL(tr[rc].r-tr[rc].l+1)*tr[now].lazy,tr[rc].lazy+=tr[now].lazy; tr[now].lazy=0; } void change(int now,int l,int r,int c) { if(tr[now].l==l&&tr[now].r==r) { tr[now].c+=LL(r-l+1)*c; tr[now].lazy+=c; return ; } int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2; if(tr[now].lazy!=0) update(now); if(r<=mid) change(lc,l,r,c); else if(l>mid) change(rc,l,r,c); else change(lc,l,mid,c),change(rc,mid+1,r,c); tr[now].c=tr[lc].c+tr[rc].c; } LL getsum(int now,int l,int r) { if(tr[now].l==l&&tr[now].r==r) return tr[now].c; int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2; if(tr[now].lazy!=0) update(now); if(r<=mid) return getsum(lc,l,r); else if(l>mid) return getsum(rc,l,r); else return getsum(lc,l,mid)+getsum(rc,mid+1,r); } LL solve(int x) { int tx=top[x];LL ans=0; while(tx!=1) { ans+=getsum(1,ys[tx],ys[x]); x=fa[tx];tx=top[x]; } return ans+getsum(1,ys[tx],ys[x]); } int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%lld",&s[i]); len=0;memset(last,0,sizeof(last)); for(int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); ins(x,y);ins(y,x); } fa[1]=0;dep[1]=0;pre_tree_node(1); z=0;pre_tree_edge(1,1); trlen=0;bt(1,z); for(int i=1;i<=n;i++) change(1,ys[i],ys[i],s[i]); for(int i=1;i<=m;i++) { int opt,x;LL a; scanf("%d%d",&opt,&x); if(opt==1) { scanf("%lld",&a); change(1,ys[x],ys[x],a); } if(opt==2) { scanf("%lld",&a); change(1,L[x],R[x],a); } if(opt==3) printf("%lld\n",solve(x)); } return 0; }

BZOJ4034: [HAOI2015]樹上操作