【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的路径数量。

Sample Input

3 3
1 2 3
1 2
1 3

Sample Output

2

HINT

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

题解:本题可以用各种O(nlogn)的算法水过,但是O(n)当然也可以搞~

用我们在DFS的时候,始终维护这样一个队列,使它是一条连续的链,且队列中点的权值和不超过S,具体做法如下

在DFS进栈的时候,我们将这个点压入队尾,并不断弹出队首直到队列的权值和≤S,并更新答案

在DFS弹栈的时候,我们将这个点从队尾弹出,并将队列恢复成这个点进栈之前的样子(由于后进来的元素都在这个点之后,所以不会修改队列中这个点前面的点,所以只需要记录一下当时的队首位置就行了)

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn=100010;
int n,m,cnt,h,t,top,ans;
int fa[maxn],to[maxn],next[maxn],v[maxn],head[maxn],q[maxn],dep[maxn];
void add(int a,int b)
{
	to[cnt]=b;
	next[cnt]=head[a];
	head[a]=cnt++;
}
void dfs(int x)
{
	int temp=h,i;
	q[++t]=x;
	while(dep[x]-dep[q[h]]>m)	h++;
	if(dep[x]-dep[q[h]]==m)	ans++;
	for(i=head[x];i!=-1;i=next[i])
	{
		dep[to[i]]=dep[x]+v[to[i]];
		dfs(to[i]);
	}
	h=temp,t--;
}
int main()
{
	scanf("%d%d",&n,&m);
	int i,a,b,c;
	for(i=1;i<=n;i++)	scanf("%d",&v[i]);
	memset(head,-1,sizeof(head));
	for(i=1;i<n;i++)
	{
		scanf("%d%d",&a,&b);
		add(a,b);
	}
	dep[1]=v[1],h=0,t=0,dfs(1);
	printf("%d",ans);
	return 0;
}
时间: 2024-08-24 06:31:07

【BZOJ2783】[JLOI2012]树 DFS+栈+队列的相关文章

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]树_树的遍历

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

2783: [JLOI2012]树( dfs + BST )

直接DFS, 然后用set维护一下就好了.... O(nlogn) -------------------------------------------------------------------------------- #include<bits/stdc++.h> #define rep(i, n) for(int i = 0; i < n; ++i) #define clr(x, c) memset(x, c, sizeof(x)) #define foreach(i, x

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 问题描述: 把一个正整数分成一列连续的正整数之和.这个数列必须包含至少两个正整数.你需要求出这个数列的最小长度.如果这个数列不存在则输出-

【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

BZOJ 2783 JLOI2012 树 DFS

题目大意:给定一棵有根树,每个节点有权值,求有多少链上的权值和为S,要求链上节点的深度必须单调(即这条链由某个节点出发指向根) DFS一遍,当深搜到一个点时将这个点加入队列,同时队头向后调整,使队列中元素之和<=s,记录ans 当一个点出栈时将队尾删除,同时队头向前调整,使队列中元素之和刚好<=s 这题1s略卡时间...不过我旁边的哥们用nlogn的算法超时700ms过去的0.0 这怎么过去的0.0 误差也太大了吧0.0 #include<cstdio> #include<c

洛谷 P3252 [JLOI2012]树

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

【C/C++学院】0828-STL入门与简介/STL容器概念/容器迭代器仿函数算法STL概念例子/栈队列双端队列优先队列/数据结构堆的概念/红黑树容器

STL入门与简介 #include<iostream> #include <vector>//容器 #include<array>//数组 #include <algorithm>//算法 using namespace std; //实现一个类模板,专门实现打印的功能 template<class T> //类模板实现了方法 class myvectorprint { public: void operator ()(const T &

java面向对象的栈 队列 优先级队列的比较

栈 队列 有序队列数据结构的生命周期比那些数据库类型的结构(比如链表,树)要短得多.在程序操作执行期间他们才被创建,通常用他们去执行某项特殊的任务:当完成任务之后,他们就会被销毁.这三个数据结构还有一个特点就是访问是受到限制的,即在特定时刻只有一个数据项可以被读取或者被删除,但是所谓的移除并不是真的删除,数据项依然在这些数据结构中,只不过因为指针已经指向其他数据项,没有办法访问到,当添加新的数据项时,当初移除的数据项被替代从而永远消失. 栈 队列 优先级队列的模拟思想 1.栈:栈遵循先进后出(F