[HAOI2015]树上操作
这是一道裸的树链剖分,但是15年HA好像还没有普及这个,连wmd神犇也是写的 O( n√n ) 的算法,还因为栈空间被卡到50分。
但是不得不说HAOI2015的难度真的非常高,至少对我来说,而wmd即使这样也依然拿到了250分,实际上他应得350分,%%%。
子树修改是一般的板子题不会有的操作,还是我对板子的认识有错误也有可能。
根据第二次dfs的编号方式,可以发现,一颗子树中的所有节点编号也是连续的一段,这样就也把子树修改对应到区间修改了。
我蛮久没写过树剖了。
写好板子!
// q.c #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<algorithm> #include<vector> using namespace std; typedef long long LL; const int M=100000+10; int n,m,lable,w[M],fa[M],son[M],dep[M],size[M],id[M],top[M],pos[M],ch[M]; vector<int> G[M]; void dfs1(int u,int f,int d) { fa[u]=f,dep[u]=d,size[u]=1; for(int i=0,s=(int)G[u].size();i<s;i++) { int v=G[u][i]; if(!fa[v]) { dfs1(v,u,d+1); if(size[v]>size[son[u]]||!son[u]) son[u]=v; size[u]+=size[v]; } } } void dfs2(int u,int tp) { top[u]=tp,id[u]=ch[u]=++lable,pos[lable]=u; if(!son[u]) return ; dfs2(son[u],tp); ch[u]=max(ch[u],ch[son[u]]); for(int i=0,s=(int)G[u].size();i<s;i++) { int v=G[u][i]; if(v!=fa[u]&&v!=son[u]) { dfs2(v,v); ch[u]=max(ch[u],ch[v]); } } } struct Node { int l,r; LL sum,lazy; Node():l(0),r(0),sum(0),lazy(0) {} }; struct SegmentTree { Node nd[M<<2]; void update(int o) { nd[o].sum=nd[o<<1].sum+nd[o<<1^1].sum; } void pushdown(int o) { nd[o<<1].sum+=nd[o].lazy*(nd[o<<1].r-nd[o<<1].l+1); nd[o<<1^1].sum+=nd[o].lazy*(nd[o<<1^1].r-nd[o<<1^1].l+1); nd[o<<1].lazy+=nd[o].lazy; nd[o<<1^1].lazy+=nd[o].lazy; nd[o].lazy=0; } void build(int o,int l,int r) { nd[o].l=l,nd[o].r=r; if(l==r) nd[o].sum=w[pos[l]]; else { int mid=(l+r)>>1; build(o<<1,l,mid); build(o<<1^1,mid+1,r); update(o); } } void add(int o,int l,int r,int k) { if(l<=nd[o].l&&nd[o].r<=r) { nd[o].sum+=(LL)k*(nd[o].r-nd[o].l+1); nd[o].lazy+=k; return ; } else { if(nd[o].lazy) pushdown(o); int mid=(nd[o].l+nd[o].r)>>1; if(l<=mid) add(o<<1,l,r,k); if(r>mid) add(o<<1^1,l,r,k); update(o); } } LL query(int o,int l,int r) { if(l<=nd[o].l&&nd[o].r<=r) return nd[o].sum; else { if(nd[o].lazy) pushdown(o); LL ans=0; int mid=(nd[o].l+nd[o].r)>>1; if(l<=mid) ans+=query(o<<1,l,r); if(r>mid) ans+=query(o<<1^1,l,r); return ans; } } }t; void Add1(int a,int b) { t.add(1,id[a],id[a],b); } void Add2(int a,int b) { t.add(1,id[a],ch[a],b); } LL Query(int a,int b) { LL ans=0; while(top[a]!=top[b]) { if(dep[top[a]]<dep[top[b]]) swap(a,b); ans+=t.query(1,id[top[a]],id[a]); a=fa[top[a]]; } if(dep[a]>dep[b]) swap(a,b); return ans+t.query(1,id[a],id[b]); } int main() { freopen("haoi2015_t2.in","r",stdin); freopen("haoi2015_t2.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&w[i]); int opt,x,a,b; for(int i=1;i<n;i++) { scanf("%d%d",&a,&b); G[a].push_back(b); G[b].push_back(a); } dfs1(1,-1,0),dfs2(1,1),t.build(1,1,n); for(int i=1;i<=m;i++) { scanf("%d",&opt); if(opt==1) scanf("%d%d",&x,&a),Add1(x,a); else if(opt==2) scanf("%d%d",&x,&a),Add2(x,a); else scanf("%d",&x),printf("%lld\n",Query(1,x)); } return 0; }