[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;
}

浙公网安备 33010602011771号