1. 程式人生 > 實用技巧 >[洛谷P3252] [JLOI2012] 樹

[洛谷P3252] [JLOI2012] 樹

[洛谷P3252] [JLOI2012] 樹

給定一個值\(S\)和一棵樹。在樹的每個節點有一個正整數,問有多少條路徑的節點總和達到\(S\)
 路徑中節點的深度必須是升序的。假設節點\(1\)是根節點,根的深度是\(0\),它的兒子節點的深度為\(1\)
 路徑不必一定從根節點開始。

Input

第一行是兩個整數\(N\)\(S\),其中\(N\)是樹的節點數。
 第二行是\(N\)個正整數,第\(i\)個整數表示節點\(i\)的正整數。
 接下來的\(N-1\)行每行是\(2\)個整數\(x\)\(y\),表示\(y\)\(x\)的兒子。

Output

輸出路徑節點總和為\(S\)

的路徑數量。

Example

輸入 #1

\(3\) \(3\)
\(1\) \(2\) \(3\)
\(1\) \(2\)
\(1\) \(3\)

輸出 #1

\(2\)

Scoring

對於\(100%\)資料,\(N≤100000\),所有權值以及\(S\)都不超過\(1000\)

注意:是總和剛好為\(S\),不是\(≥S\)

剛開始審題看成\(≥S\)了orz

咱也不會啥高階做法,暴力。

盲猜權值無負數,這樣的話選一個點,往下搜,搜到大於\(S\)就return,剛好等於\(S\)就ans++

期望複雜度\(O(nlogn)\),資料很水,沒有鏈,不會卡成\(O(n^2)\)

程式碼:

#include<bits/stdc++.h>
using namespace std;

int n, s, x, y, cnt;
int v[100005];
int fa[100005];
vector <int> p[100005];

void dfs(int pl, int sum) {
	sum += v[pl];
	if (sum > s) return;
	if (sum == s) {cnt++; return;}
	for (int i = 0; i < p[pl].size(); i++) {
		if (p[pl][i] != fa[pl])
			dfs(p[pl][i], sum);
	}
}

int main() {
	scanf("%d %d", &n, &s);
	for (int i = 1; i <= n; i++) scanf("%d", &v[i]);
	for (int i = 1; i < n; i++) {
		scanf("%d %d", &x, &y);
		fa[y] = x; 
		p[x].push_back(y);
	}
	for (int i = 1; i <= n; i++) dfs(i, 0);
	printf("%d", cnt);
	return 0;
}