bzoj 2783 //2783: [JLOI2012]树 dfs 深搜+剪枝/树上倍增

bzoj 2783 //2783: [JLOI2012]树   //在线测评地址https://www.lydsy.com/JudgeOnline/problem.php?id=2783

更多题解,详见https://blog.csdn.net/mrcrack/article/details/90228694BZOJ刷题记录

方法一:dfs 深搜+剪枝   技术含量低,但掌握不易:

2776 kb 368 ms C++/Edit 726 B

//2783: [JLOI2012]树
//在线测评地址https://www.lydsy.com/JudgeOnline/problem.php?id=2783
//看来半天,文不对题,看到后面才发现,之前内容无用,题目才刚刚开始
//简单画了图,题意弄明白了。
//n=100000,s=1000,10^5*10^3=10^8 int不会溢出。
//此文https://www.luogu.org/problemnew/solution/P3252   作者: enceladus 更新时间: 2018-09-04 10:43 思路写得不错,摘抄如下

bzoj 2783 //2783: [JLOI2012]树 dfs 深搜+剪枝/树上倍增_第1张图片

bzoj 2783 //2783: [JLOI2012]树 dfs 深搜+剪枝/树上倍增_第2张图片

bzoj 2783 //2783: [JLOI2012]树 dfs 深搜+剪枝/树上倍增_第3张图片


//样例通过,提交AC.2019-10-27 22:20
//回过头想了想,深搜的技术含量是比较低,但能编得好的又有几人呢。
#include
#include
#define maxn 100010
int n,s,head[maxn],cnt=0,w[maxn],fa[maxn],ans=0;
struct node{
    int to,next;
}e[maxn];
void add_edge(int u,int v){
    cnt++,e[cnt].to=v,e[cnt].next=head[u],head[u]=cnt;
}
void dfs(int x,int d){
    int b,v;
    if(d>s)return;
    if(d==s)ans++;
    for(b=head[x];b;b=e[b].next){
        v=e[b].to;
        if(v!=fa[x])
            dfs(v,d+w[v]);
    }
}
int main(){
    int i,x,y;
    memset(head,0,sizeof(head));
    scanf("%d%d",&n,&s);
    for(i=1;i<=n;i++)scanf("%d",&w[i]);
    for(i=1;i         scanf("%d%d",&x,&y);
        add_edge(x,y),fa[y]=x;
    }
    for(i=1;i<=n;i++)dfs(i,w[i]);
    printf("%d\n",ans);
    return 0;
}

方法二:树上倍增

18524 kb 496 ms C++/Edit 1032 B

//树上倍增,核心就是+,2^j-1+2^j-1=2^j

//log10^5=17
//此文https://www.luogu.org/problemnew/solution/P3252?page=3 作者: _OiNksEduCn_ 更新时间: 2019-08-25 16:46代码写得不错,思路写得不错。
/*

bzoj 2783 //2783: [JLOI2012]树 dfs 深搜+剪枝/树上倍增_第4张图片

*/
//样例通过,提交AC.2019-10-30 19:16
#include
#include
#define maxn 100100
int fa[maxn][20],w[maxn][20],n,s,head[maxn],cnt=0,ans=0;
struct node{
    int to,next;
}e[maxn];
void add_edge(int u,int v){
    cnt++,e[cnt].to=v,e[cnt].next=head[u],head[u]=cnt;
}
void dfs(int x,int father){
    int i,j,b,v,now,p;
    fa[x][0]=father;//漏了此句
    for(i=1;i<=17;i++){
        fa[x][i]=fa[fa[x][i-1]][i-1];
        w[x][i]=w[x][i-1]+w[fa[x][i-1]][i-1];
    }
    now=s,p=x;
    for(i=17;i>=0;i--)
        if(fa[p][i]&&now>w[p][i])
            now-=w[p][i],p=fa[p][i];//此处错写成now-=w[p][i],p=fa[p][i-1];
    if(now==w[p][0])ans++;//此处错写成if(now=w[p][0])ans++;这种昏招都有
    for(b=head[x];b;b=e[b].next){
        v=e[b].to;
        if(v!=father)
            dfs(v,x);
    }
}
int main(){
    int i,u,v;
    memset(head,0,sizeof(head));
    scanf("%d%d",&n,&s);
    for(i=1;i<=n;i++)scanf("%d",&w[i][0]);
    for(i=1;i     dfs(1,0);
    printf("%d\n",ans);
    return 0;
}

你可能感兴趣的:(跟着大佬学算法)