题解 P3178 【[HAOI2015]树上操作】

我不是柳橙汁

2017-10-12 21:21:15

Solution

# 这道题是裸的树链剖分算法 # 这道题是裸的树链剖分算法 # 这道题是裸的树链剖分算法 我觉得还可以。因为我读优忘记写负数了。 然后对于点操作,线段树从自己到自己增加就行了。 然后和 P3384 【模板】树链剖分 一模一样的做法,简直就是双倍经验 ```cpp #include<iostream> #include<cstdio> using namespace std; struct edge{ long long to,next; }e[200010]; long long n,m,len,tot; long long a[100010],tree[400010],lazy[400010]; long long head[100010],real[100010],id[100010],fa[100010],hson[100010],dep[100010],size[100010],top[100010]; long long v_in(){//快读 long long sum=0,f=1; char ch=getchar(); while (ch<'0'||ch>'9'){ if (ch=='-') f*=-1; ch=getchar(); } while (ch>='0'&&ch<='9'){ sum=sum*10+ch-'0'; ch=getchar(); } return sum*f; } void add(long long u,long long v){//加边 e[++len].to=v; e[len].next=head[u]; head[u]=len; } /*线段树(Segment Tree)*/ void pushup(long long rt){//上推 tree[rt]=tree[rt<<1]+tree[rt<<1|1]; } void pushdown(long long rt,long long ln,long long rn){//下推 if (lazy[rt]){ tree[rt<<1]+=lazy[rt]*ln; tree[rt<<1|1]+=lazy[rt]*rn; lazy[rt<<1]+=lazy[rt]; lazy[rt<<1|1]+=lazy[rt]; lazy[rt]=0; } } void build(long long l,long long r,long long rt){//建树 if (l==r){ tree[rt]=a[real[l]]; return; } long long mid=(l+r)>>1; build(l,mid,rt<<1); build(mid+1,r,rt<<1|1); pushup(rt); } void update(long long l,long long r,long long rt,long long left,long long right,long long c){//修改操作 if (l>=left&&r<=right){ tree[rt]+=c*(r-l+1); lazy[rt]+=c; return; } long long mid=(l+r)>>1; pushdown(rt,mid-l+1,r-mid); if (mid>=left) update(l,mid,rt<<1,left,right,c); if (mid+1<=right) update(mid+1,r,rt<<1|1,left,right,c); pushup(rt); } long long query(long long l,long long r,long long rt,long long left,long long right){//询问操作 if (l>=left&&r<=right) return tree[rt]; long long mid=(l+r)>>1,ans=0; pushdown(rt,mid-l+1,r-mid); if (mid>=left) ans+=query(l,mid,rt<<1,left,right); if (mid+1<=right) ans+=query(mid+1,r,rt<<1|1,left,right); pushup(rt); return ans; } /*树链剖分*/ void dfs1(long long u,long long f){//第一遍深搜(建树,记录fa,size,dep,hson) fa[u]=f; size[u]=1; for (long long i=head[u];i!=0;i=e[i].next){ long long v=e[i].to; if (fa[u]!=v){ dep[v]=dep[u]+1; dfs1(v,u); if (hson[u]==0||size[hson[u]]<size[v]) hson[u]=v; size[u]+=size[v]; } } } void dfs2(long long u,long long anc){//第二遍深搜(分链,重新编号,记录top,id,real) top[u]=anc; id[u]=++tot; real[tot]=u; if (hson[u]==0) return; dfs2(hson[u],anc); for (long long i=head[u];i!=0;i=e[i].next){ long long v=e[i].to; if (v!=fa[u]&&v!=hson[u]) dfs2(v,v); } } void point_add(){//1操作 long long x=v_in(),w=v_in(); update(1,n,1,id[x],id[x],w); } void tree_add(){//2操作 long long x=v_in(),w=v_in(); update(1,n,1,id[x],id[x]+size[x]-1,w); } void chain_query(){//3操作 long long u=v_in(); long long tu=top[u],ans=0; while (tu!=1){ ans+=query(1,n,1,id[tu],id[u]); u=fa[tu]; tu=top[u]; } ans+=query(1,n,1,id[1],id[u]); printf("%lld\n",ans); } main(){ n=v_in(); m=v_in(); for (long long i=1;i<=n;i++) a[i]=v_in(); for (long long i=1;i<n;i++){ long long u=v_in(),v=v_in(); add(u,v);//无向边 add(v,u); } dep[1]=1; dfs1(1,0); dfs2(1,1); build(1,n,1); for (long long i=1;i<=m;i++){ long long q=v_in(); if (q==1) point_add(); else if (q==2) tree_add(); else chain_query(); } return 0; } ```