【JLOI2012】【BZOJ2783】树

Description

在这个问题中,给定一个值S和一棵树。在树的每个节点有一个正整数,问有多少条路径的节点总和达到S。路径中节点的深度必须是升序的。假设节点1是根节点,根的深度是0,它的儿子节点的深度为1。路径不必一定从根节点开始。

Input

   第一行是两个整数N和S,其中N是树的节点数。
   第二行是N个正整数,第i个整数表示节点i的正整数。
   接下来的N-1行每行是2个整数x和y,表示y是x的儿子。

Output

   输出路径节点总和为S的路径数量。

Sample Input

3 3

1 2 3

1 2

1 3

Sample Output

2

HINT

对于100%数据,N≤100000,所有权值以及S都不超过1000。

由于路径必须是深到浅的一条链

所以DFS+set维护出现过的值就行了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#define MAXN 100010
using namespace std;
int n,s,top;
int val[MAXN],dis[MAXN],fa[MAXN];
int root;
long long ans;
multiset<int> S;
struct edge
{
    int to;
    edge *next;
}e[MAXN<<1],*prev[MAXN];
void insert(int u,int v)
{
    e[++top].to=v;e[top].next=prev[u];prev[u]=&e[top];
}
void dfs(int x)
{
    for (edge *i=prev[x];i;i=i->next)
    {
        dis[i->to]=dis[x]+val[i->to];
        S.insert(dis[i->to]);
        if (S.find(dis[i->to]-s)!=S.end())  ans++;
        dfs(i->to);
        S.erase(dis[i->to]);
    }
}
int main()
{
    scanf("%d%d",&n,&s);S.clear();
    for (int i=1;i<=n;i++)  scanf("%d",&val[i]);
    for (int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        fa[y]=x;insert(x,y);
    }
    for (int i=1;i<=n;i++)
        if (!fa[i]) root=i;
    dis[root]=val[root];S.insert(0);S.insert(val[root]);
    if (S.find(dis[root]-s)!=S.end())   ans++;
    dfs(root);
    printf("%lld\n",ans);
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-09-30 14:56:22

【JLOI2012】【BZOJ2783】树的相关文章

「JLOI2012」树

「JLOI2012」树 传送门 不得不说这题的数据是真的水... 我们可以想到很明确的一条思路:枚举每一个点向根节点跳,知道路径和不小于 \(s\),恰好等于 \(s\) 就直接加答案. 跳的过程可以用倍增搞,但是暴力跳也可以过(这棵树的高度比较友好啊) 我只给了暴力的代码,倍增的懒得去写了... 参考代码: /*-------------------------------- Code name: B.cpp Author: The Ace Bee This code is made by T

bzoj2783【JLOI2012】树

2783: [JLOI2012]树 Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 668  Solved: 389 [Submit][Status][Discuss] Description 数列 提交文件:sequence.pas/c/cpp 输入文件:sequence.in 输出文件:sequence.out 问题描述: 把一个正整数分成一列连续的正整数之和.这个数列必须包含至少两个正整数.你需要求出这个数列的最小长度.如果这个数列不存在则输

bzoj2783 树

第一行是两个整数N和S,其中N是树的节点数. 第二行是N个正整数,第i个整数表示节点i的正整数. 接下来的N-1行每行是2个整数x和y,表示y是x的儿子. 输出格式: 输出路径节点总和为S的路径数量. 输入样例: 输出样例: 3 3 1 2 3 1 2 1 3 2 数据范围: 对于30%数据,N≤100: 对于60%数据,N≤1000: 对于100%数据,N≤100000,所有权值以及S都不超过1000. 倍增预处理出每个节点向上走2^k步到达的点和权值和,对每个点二分向上能走(权值和小于S)的

【BZOJ2783】[JLOI2012]树 DFS+栈+队列

[BZOJ2783][JLOI2012]树 Description 在这个问题中,给定一个值S和一棵树.在树的每个节点有一个正整数,问有多少条路径的节点总和达到S.路径中节点的深度必须是升序的.假设节点1是根节点,根的深度是0,它的儿子节点的深度为1.路径不必一定从根节点开始. Input 第一行是两个整数N和S,其中N是树的节点数. 第二行是N个正整数,第i个整数表示节点i的正整数. 接下来的N-1行每行是2个整数x和y,表示y是x的儿子. Output 输出路径节点总和为S的路径数量. Sa

[bzoj2783][JLOI2012]树_树的遍历

树 bzoj2783 JLOI2012 题目大意:给定一棵n个点的树.求满足条件的路径条数.说一个路径是满足条件的,当且仅当这条路径上每个节点深度依次递增且点权和为S. 注释:$1\le n\le 10^5$,$1\le S,val_i\le 10^3$. 想法:翻lijinnn的blog翻到的水题. 我们直接遍历整棵树,遍历的时候维护全局桶.然后在回溯的时候将这个点对应的dis删除.这样遍历到每个点时桶内对应的就是这个点到根节点的dis桶,直接统计答案即可. 最后,附上丑陋的代码... ...

bzoj2783: [JLOI2012]树

2783: [JLOI2012]树 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 753  Solved: 447[Submit][Status][Discuss] Description 数列 提交文件:sequence.pas/c/cpp 输入文件:sequence.in 输出文件:sequence.out 问题描述: 把一个正整数分成一列连续的正整数之和.这个数列必须包含至少两个正整数.你需要求出这个数列的最小长度.如果这个数列不存在则输出-

BZOJ2783: [JLOI2012]树 dfs+set

2783: [JLOI2012]树 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 588  Solved: 347 Description 数列 提交文件:sequence.pas/c/cpp 输入文件:sequence.in 输出文件:sequence.out 问题描述: 把一个正整数分成一列连续的正整数之和.这个数列必须包含至少两个正整数.你需要求出这个数列的最小长度.如果这个数列不存在则输出-1. 输入格式: 每行包含一个正整数n. 每个文件

【bzoj2783】【JLOI2012】【树】【set】

在这个问题中,给定一个值S和一棵树.在树的每个节点有一个正整数,问有多少条路径的节点总和达到S.路径中节点的深度必须是升序的.假设节点1是根节点,根的深度是0,它的儿子节点的深度为1.路径不必一定从根节点开始. Input 第一行是两个整数N和S,其中N是树的节点数. 第二行是N个正整数,第i个整数表示节点i的正整数. 接下来的N-1行每行是2个整数x和y,表示y是x的儿子. Output 输出路径节点总和为S的路径数量. Sample Input 3 3 1 2 3 1 2 1 3 Sampl

【dfs】【哈希表】bzoj2783 [JLOI2012]树

因为所有点权都是正的,所以对每个结点u来说,每条从根到它的路径上只有最多一个结点v符合d(u,v)=S. 所以我们可以边dfs边把每个结点的前缀和pre[u]存到一个数据结构里面,同时查询pre[u]-S是否存在. 数据结构用set.hashtable(随便卡)(需要支持删除,由于总是删掉最后一个,因此可以实现)都行. #include<cstdio> #include<cstring> using namespace std; #define MAXN 100001 #defin