卧薪尝胆,厚积薄发。
JLOI2012 树
Date: Wed Sep 19 08:19:53 CST 2018 In Category: NoCategory

Description:

一棵树每个节点有权值,问有多少条路径权值和为 $S$ ,要求路径中的点深度递增。
$1\le n \le 100000$

Solution:

既然路径中的点深度递增那就可以树上前缀和来做,可以用 $map$ 启发式合并得到那个节点所有子树的树上前缀和查一下就行了。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<map>
#include<cstring>
using namespace std;
int n,m;
#define MAXN 100010
int val[MAXN];
struct edge
{
int to,nxt;
}e[MAXN << 1];
int edgenum = 0;
int lin[MAXN] = {0};
void add(int a,int b)
{
++edgenum;e[edgenum].to = b;e[edgenum].nxt = lin[a];lin[a] = edgenum;
++edgenum;e[edgenum].to = a;e[edgenum].nxt = lin[b];lin[b] = edgenum;
return;
}
map<int,long long> s[MAXN];
int rt[MAXN];
long long dep[MAXN];
bool vis[MAXN];
void merge(int &rt,int &son)
{
if(s[rt].size() < s[son].size())swap(rt,son);
for(map<int,long long>::iterator i = s[son].begin();i != s[son].end();++i)
{
s[rt][i -> first] += i -> second;
}
return;
}
long long ans = 0;
void dfs(int k,int depth)
{
vis[k] = true;dep[k] = depth;
for(int i = lin[k];i != 0;i = e[i].nxt)
{
if(vis[e[i].to])continue;
dfs(e[i].to,depth + val[e[i].to]);
merge(rt[k],rt[e[i].to]);
}
++s[rt[k]][dep[k]];
map<int,long long>::iterator i = s[rt[k]].find(dep[k] + m);
if(i != s[rt[k]].end())ans += i -> second;
return;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;++i)scanf("%d",&val[i]);
int a,b;
for(int i = 1;i < n;++i)
{
scanf("%d%d",&a,&b);
add(a,b);
}
for(int i = 1;i <= n;++i)rt[i] = i;
dfs(1,val[1]);
cout << ans + s[rt[1]][m] << endl;
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡