dfs序

cn是大帅哥886發表於2024-07-23

定義


每一個節點記錄:
st[i]:第一次遍歷到這個點的時間戳
ed[i]:離開這個點的時候的時間戳

dfs序是一個連續的序列,L=st[u],R=ed[u],把樹上操作轉移到序列中

dfs序的七種常見模型


點修改+子樹和查詢


(實際上是樹狀陣列的操作)

單點修改
add(st[x], +-v)


查詢子樹和
ask(ed[x])-ask(st[x-1])

第1題 樹查詢 檢視測評資料資訊

有一棵樹,含有n個節點,和n-1條邊。

這棵樹的根節點編號為root,每個節點都有一個權值,第i個節點的權值為v[i]。

現在有m個操作,每個操作有如下兩種型別:

1 a x :表示將節點a的權值加上x

2 a :表示求a節點的子樹上所有節點的和(包括a節點本身的權重)。

輸入格式

第一行給出三個正整數n,m,root,表示樹的節點數、操作次數、和這棵樹的根節點

第二行給出n個正整數,第2個正整數表示第i個節點的權值v[i]

下面n-1行每行兩個正整數u,v,表示邊的兩個端點

接下來m行,每行給出一個操作

部分資料:1<=n,m<=100

1<=n,m<=1e6, 1<=root<=n

1<=u,v,a<=n

-1e6<=v[i],x<=1e6

輸出格式

對於每個型別為2的操作,輸出一行一個正整數,表示以為根的子樹的所有節點的權值和

輸入/輸出例子1

輸入:

5 6 1

1 2 3 4 5

1 3

1 2

2 4

2 5

1 2 10

1 3 10

1 4 5

1 5 1

2 3

2 2

輸出:

13

27

樣例解釋

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5;

int n, m, root, v[N], u1, v1, x, k, op;
int dfn[N], st[N], ed[N], tim=0, s[N];
vector<int> a[N];
void dfs(int u, int fa)
{
	st[u]=++tim;
	dfn[tim]=u;
	
	for (int i=0; i<a[u].size(); i++)
	{
		int v=a[u][i];
		if (v!=fa) dfs(v, u);
	}
	
	ed[u]=tim;
}
int lowbit(int x)
{
	return x&(-x);
}
void add(int x, int k)
{
	for (int i=x; i<=n; i+=lowbit(i)) s[i]+=k;
}
int ask(int x, int y)
{
	int res=0;
	for (int i=y; i>=1; i-=lowbit(i)) res+=s[i];
	for (int i=x-1; i>=1; i-=lowbit(i)) res-=s[i];
	
	return res;
}
signed main()
{
	scanf("%d%d%d", &n, &m, &root);
	for (int i=1; i<=n; i++) scanf("%lld", &v[i]);
	for (int i=1; i<n; i++)
	{
		scanf("%d%d", &u1, &v1);
		a[u1].push_back(v1);
		a[v1].push_back(u1);
	}
	
	dfs(root, -1);
	for (int i=1; i<=n; i++) add(st[i], v[i]);
	
	while (m--)
	{
		scanf("%d", &op);
		if (op==1)
		{
			scanf("%d%lld", &x, &k);
			add(st[x], k);
		}
		else if (op==2)
		{
			scanf("%d", &x);
			printf("%lld\n", ask(st[x], ed[x]));
		}
	}
	return 0;
}

  

相關文章