#144. DFS 序 1

#144. DFS 序 1

好久没做 d f s dfs 序了,复习一波。

d f s dfs 序说白了就是对一棵树进行 d f s dfs 时结点被遍历的顺序。

d f s dfs 序的性质:对于一棵子树的遍历顺序一定是连续的。

因此我们可以记录开始进入以 u u 为根的子树的顺序 i n [ u ] in[u] ,和遍历 u u 的最后一个叶子结点的顺序 o u t [ u ] out[u] 。这里我们就可以实现对一棵树进行区间操作了。

这里的题目是单点更新,区间查询,显然 d f s dfs 序转树状数组就是板子题。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair<int,int>
#define fi first
#define se second
#define pb push_back
#define lowbit(x) x&(-x)
#define il inline
template<class T>
inline void read(T &x){ 
	x=0;int w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
	for(;ch>='0'&&ch<='9';ch=getchar())
		x=(x<<3)+(x<<1)+(ch&15);
	x*=w; 
}
ll a[N],tr[N];
int in[N],out[N],h[N];
int tot,n,m,cnt,st;
struct edge{
	int to,nt;
}e[N<<1]; 
il void add(int u,int v){
	e[++cnt]={v,h[u]},h[u]=cnt;
}
void upd(int x,int k){	//单点更新. 
	while(x<=n){
	   tr[x]+=k;
	   x+=lowbit(x);
	}
}
ll query(int x){	//求和. 
	ll ans=0;
	while(x){
	   ans+=tr[x];
	   x-=lowbit(x);
	}
	return ans;
}
void dfs(int u,int fa){	//求出dfx序,构造树状数组. 
	in[u]=++tot,upd(in[u],a[u]);
	for(int i=h[u];i;i=e[i].nt){
		if(e[i].to==fa) continue;
		dfs(e[i].to,u);
	}
	out[u]=tot;//out[u]表示以u为根的子树的最后一个结点编号,类似于区间的右端点. 
}
int main(){
	read(n),read(m),read(st);
	for(reg int i=1;i<=n;i++) read(a[i]);
	for(reg int i=1,u,v;i<n;i++)
		read(u),read(v),add(u,v),add(v,u);
	dfs(st,0);
	while(m--){
		int op,a,x;
		read(op),read(a);
		if(op==1) read(x),upd(in[a],x);
		else printf("%lld\n",query(out[a])-query(in[a]-1));
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45750972/article/details/107411920