洛谷P3252 [JLOI2012]树

题目描述

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

输入输出格式

输入格式:

 

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

 

输出格式:

 

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

 

输入输出样例

输入样例#1:
3 3
1 2 3
1 2
1 3
输出样例#1:
2

说明

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

 

题目大意:求树上连续一段深度递增的路径的点权和为s的条数

题解:dfs(i)以i为起点的路径有多少条 

错因:理解错了 不能用记忆化搜索

数据水暴力可过

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define LL long long
#define maxn 100008
using namespace std;

int n,s,sumedge;
int head[maxn],w[maxn];
long long ans;

struct Edge{
    int x,y,nxt;
    Edge(int x=0,int y=0,int nxt=0):
        x(x),y(y),nxt(nxt){}
}edge[maxn];

void add(int x,int y){
    edge[++sumedge]=Edge(x,y,head[x]);
    head[x]=sumedge;
}

LL dfs(int x,int sum){
    if(sum>s)return 0;
    if(sum==s)return 1;
    long long js=0;
    for(int i=head[x];i;i=edge[i].nxt){
        int v=edge[i].y;
        js+=dfs(v,sum+w[v]);
    }
    return js;
}

int main(){
    scanf("%d%d",&n,&s);
    for(int i=1;i<=n;i++)scanf("%d",&w[i]);
    for(int i=1;i<n;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);
    }
    for(int i=1;i<=n;i++)if(w[i]==s)ans++;else ans+=dfs(i,w[i]);
    cout<<ans<<endl;
    return 0;
}

树上前缀和

保存搜到i之前的祖先,累加权值,是否sum[i]-sum[祖先]=s,注意搜完时删掉祖先。

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 100008
#define LL long long
using namespace std;

int n,s,sumedge,cnt,js;
int head[maxn],w[maxn],dad[maxn],fa[maxn],sum[maxn];
LL ans;

struct Edge{
    int x,y,nxt;
    Edge(int x=0,int y=0,int nxt=0):
        x(x),y(y),nxt(nxt){}
}edge[maxn];

void add(int x,int y){
    edge[++sumedge]=Edge(x,y,head[x]);
    head[x]=sumedge;
}

void dfs(int x){
    dad[++js]=x;
    for(int i=head[x];i;i=edge[i].nxt){
        int v=edge[i].y;
        sum[v]=sum[x]+w[v];
        for(int j=js;j>=0;j--){//要循环到0,可能它自己的点权就是s 
            if(sum[v]-sum[dad[j]]==s)ans++;
            if(sum[v]-sum[dad[j]]>s)break;
        }
        dfs(v);
    }
    js--;
}

int main(){
    scanf("%d%d",&n,&s);
    for(int i=1;i<=n;i++)scanf("%d",&w[i]);
    for(int i=1;i<n;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        fa[y]=x;
        add(x,y);
    }
    sum[1]=w[1]; 
    dfs(1);
    cout<<ans<<endl;
    return 0;
}

 

posted @ 2017-09-25 17:50  ANhour  阅读(248)  评论(0编辑  收藏  举报