LOJ #145. DFS 序 2 题解
板子题。
考虑深搜,确定每个点的时间戳(即搜索顺序的编号吧)\(\operatorname{dfn}\),然后记录 \(\operatorname{size}\) 表示子树大小。为方便进一步叙述,\(\operatorname{Tree}\) 表示子树集。
时间戳的性质,其中有一: \(\forall v \in \operatorname{Tree}(u)\),\(\operatorname{dfn}(u) \leq \operatorname{dfn}(v) < \operatorname{dfn}(u) + siz(u)\). 即 \(u\) 子树内所有节点(\(v\))的 \(\operatorname{dfn}\) 是连续的。
考虑到 \(\operatorname{dfn}\) 连续,可以用线段树维护子树和变化。
时间复杂度:\(\mathcal{O}(n + m \log n)\).
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+1;
inline int read(){char ch=getchar(); int f=1; while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
int x=0; while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return x*f;}
inline void write(int x) {
if(x<0) {putchar('-');write(-x);return;}
if(x<10) {putchar(char(x%10+'0'));return;}
write(x/10);putchar(char(x%10+'0'));
}
int n,m,root,v[N],cnt;
int dfn[N],siz[N],val[N];
vector<int> G[N];
typedef long long ll;
#define L (x<<1)
#define R (x<<1)+1
struct data {
int l,r; ll sum,tag;
};
data t[N<<2];
struct BIT {
inline void update(int x) {
t[x].sum=t[L].sum+t[R].sum;
}
inline void build_tree(int x,int l,int r) {
t[x].l=l; t[x].r=r; t[x].tag=0;
if(l==r) {t[x].sum=v[val[l]]; return;}
int mid=(l+r)>>1;
build_tree(L,l,mid); build_tree(R,mid+1,r);
update(x);
}
inline void pushdown(int x) {
ll p=t[x].tag; if(!p) return;
t[L].tag+=p; t[R].tag+=p;
t[L].sum+=p*(t[L].r-t[L].l+1);
t[R].sum+=p*(t[R].r-t[R].l+1);
t[x].tag=0;
}
inline void change(int x,int l,int r,int k) {
if(l<=t[x].l && t[x].r<=r) {t[x].tag+=k; t[x].sum+=1ll*k*(t[x].r-t[x].l+1);return;}
int mid=(t[x].l+t[x].r)>>1; pushdown(x);
if(l<=mid) change(L,l,r,k);
if(r>mid) change(R,l,r,k);
update(x);
}
inline ll ask(int x,int l,int r) {
if(l<=t[x].l && t[x].r<=r) return t[x].sum;
int mid=(t[x].l+t[x].r)>>1; ll ans=0; pushdown(x);
if(l<=mid) ans+=ask(L,l,r);
if(r>mid) ans+=ask(R,l,r);
return ans;
}
} T;
inline void dfs(int x,int fa) {
dfn[x]=++cnt; val[cnt]=x; siz[x]=1;
for(int i=0;i<G[x].size();i++) {
int y=G[x][i]; if(y==fa) continue;
dfs(y,x); siz[x]+=siz[y];
}
}
int main() {
n=read(),m=read(),root=read();
for(int i=1;i<=n;i++) v[i]=read();
for(int i=1;i<n;i++) {
int u=read(),v=read();
G[u].push_back(v);
G[v].push_back(u);
} dfs(root,0);
T.build_tree(1,1,n);
while(m--) {
int op=read(),a=read(),x;
if(op==1) {
x=read();
T.change(1,dfn[a],dfn[a]+siz[a]-1,x);
} else printf("%lld\n",T.ask(1,dfn[a],dfn[a]+siz[a]-1));
}
return 0;
}
简易的代码胜过复杂的说教。