首页 > 代码库 > 【BZOJ2783】[JLOI2012]树 DFS+栈+队列
【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
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;}
【BZOJ2783】[JLOI2012]树 DFS+栈+队列
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。