zoukankan      html  css  js  c++  java
  • 洛谷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;
    }
  • 相关阅读:
    [saiku] 系统登录成功后查询Cubes
    216. Combination Sum III
    215. Kth Largest Element in an Array
    214. Shortest Palindrome
    213. House Robber II
    212. Word Search II
    211. Add and Search Word
    210. Course Schedule II
    分硬币问题
    开始学习Python
  • 原文地址:https://www.cnblogs.com/zzyh/p/7593079.html
Copyright © 2011-2022 走看看