BZOJ 2783 树

树上倍增。

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxv 100500
#define maxe 200500
using namespace std;
struct edge
{
    int v,nxt;
}e[maxe];
int n,s,w[maxv],dis[maxv],x,y,nume=0,g[maxv],root,anc[maxv][20],sum[maxv][20],ans=0;
bool vis[maxv];
void addedge(int u,int v)
{
    e[++nume].v=v;
    e[nume].nxt=g[u];
    g[u]=nume;
}
void dfs(int now)
{
    for (int i=g[now];i;i=e[i].nxt)
    {
        int v=e[i].v;
        dis[v]=dis[now]+1;
        anc[v][0]=now;
        sum[v][0]=w[now];
        dfs(v);
    }
}
int find(int x)
{
    int regis=w[x],now=x;
    for (int ee=19;ee>=0;ee--)
    {
        if (regis+sum[now][ee]<=s)
        {
            regis+=sum[now][ee];
            now=anc[now][ee];
        }
    }
    if (regis==s) return 1;
    return 0;
}
int main()
{
    scanf("%d%d",&n,&s);
    for (int i=1;i<=n;i++)
        scanf("%d",&w[i]);
    for (int i=1;i<=n-1;i++)
    {
        scanf("%d%d",&x,&y);
        addedge(x,y);
        vis[y]=true;
    }
    for (int i=1;i<=n;i++)
    {
        if (vis[i]==false)
            root=i;
    }
    dfs(root);
    for (int ee=1;ee<=19;ee++)
        for (int i=1;i<=n;i++)
        {
            anc[i][ee]=anc[anc[i][ee-1]][ee-1];
            sum[i][ee]=sum[anc[i][ee-1]][ee-1]+sum[i][ee-1];
        }
    for (int i=1;i<=n;i++)
        ans+=find(i);
    printf("%d\n",ans);
    return 0;
}
时间: 2024-11-10 01:07:28

BZOJ 2783 树的相关文章

bzoj 3083 树链剖分

首先我们先将树提出一个根变成有根树,那么我们可以通过树链剖分来实现对于子树的最小值求解,那么按照当前的根和询问的点的相对位置关系我们可以将询问变成某个子树和或者除去某颗子树之后其余的和,前者直接询问区间,后者询问区间的补集. /************************************************************** Problem: 3083 User: BLADEVIL Language: C++ Result: Accepted Time:6412 ms

BZOJ 2783 JLOI 2012 树 乘+二分法

标题效果:鉴于一棵树和一个整数s,问中有树木几个这样的路径,点和担保路径==s,深度增量点. 这一数额的输出. 思维:用加倍的想法,我们可以O(logn)在时间找点他第一n.因为点权仅仅能是正的,满足二分性质.然后对于每个点二分.看看有没有路径的权值和是S.统计答案,输出. CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M

BZOJ 2783 JLOI 2012 树 倍增+二分

题目大意:给出一棵树和一个整数s,问在树上有几条这样路径,保证路径上的点权和==s,点的深度递增.输出这个数量. 思路:利用倍增的思想,我们能在O(logn)的时间内求出一个点到他的第n个爸爸之间所有点的点权之和.由于点权只能是正的,满足二分性质.然后对于每一个点二分,看看有没有路径的权值和是S,统计答案,输出. CODE: #include <cstdio> #include <cstring> #include <iostream> #include <alg

BZOJ 2783 JLOI2012 树 DFS

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

BZOJ 2783 [JLOI2012]树

题解:set就好 #include<iostream> #include<cstdio> #include<map> #include<cstring> using namespace std; const int maxn=100009; int n,k; int root; int w[maxn]; int notroot[maxn]; int ans; int cntedge; int head[maxn]; int to[maxn<<1]

BZOJ 1036 树链剖分模板题

BZOJ 1036 题意:一棵树,每个点有权值,三种操作:修改一个点的值:询问一条链上最大值:询问一条链上权值和. tags:模板题 // bzoj 1036 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define FF(i,a,b) for (int i=a;i<=b;i++) #define F(i,b,a)

(Dfs) bzoj 2783

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

spoj 375 AND bzoj 1036 树链剖分

树链剖分的入门题目,自己写了下感觉还是挺好写的,不过真的有点长... spoj 375 边有权值: 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 6 const int INF = -999999999; 7 const int N = 10001; 8 int head[N]; 9 int sz[N]; 10 int depth[N]; 1

bzoj 3196 树套树模板

然而我还是在继续刷水题... 终于解开了区间第k大的心结... 比较裸的线段树套平衡树,比较不好想的是求区间第k大时需要二分一下答案,然后问题就转化为了第一个操作.复杂度nlog3n.跑的比较慢... 在查前驱后继的时候写错了...如果要直接赋值ans的话前驱是k[x]<=z,后继是k[x]<z,如果都写<的话需要取max和min...(不是第一次犯这种错了) 1 #include<iostream> 2 #include<cstdio> 3 #include&l