(模板)hdoj5977 Garden of Eden(点分治)

题目链接:https://vjudge.net/problem/HDU-5977

题意:给一颗树,每个结点上有一个权值a[i],a[i]<=10,求有多少条路径满足这条路径上所有权值的结点都出现了。

思路:

  首先利用二进制的思想,将a[i]转化为1<<(a[i]-1)。我们在子树中,计算出结点到重心的路径,用二进制表示,比如011表示该路径中权值3没有出现、权值1和2出现。因为k最大为10,那么我们在计算结果时把所有可能枚举一遍,也就1024,如果枚举的i和当前路径取或后=(1<<k)-1,那么该路径满足要求,加上即可。具体实现时用桶记录信息,mine[i]表示权值为i的路径的个数。

  另外,题目规定不同的路径仅当起点终点均不同,所以(1,2)和(2,1)是两个合法解,我的处理是先getdis一遍得到桶的信息,处理子结点,现将该子结点的子树的信息清除掉,即change函数,dfs之后再恢复回来。这种处理很重要,所以把这题当作模板记录一下。

  不得不说,写点分治时要非常细心,我总是半小时代码,1小时改bug,老是一些简单错误。

AC代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

typedef long long LL;
const int maxn=50005;
const int inf=0x3f3f3f3f;
struct node{
    int v,nex;
}edge[maxn<<1];

int n,k,cnt,head[maxn],a[maxn],sz[maxn],mson[maxn],Min,size,root;
int vis[maxn],flag;
LL ans,mine[1050];

void adde(int u,int v){
    edge[++cnt].v=v;
    edge[cnt].nex=head[u];
    head[u]=cnt;
}

void getroot(int u,int fa){
    sz[u]=1,mson[u]=0;
    for(int i=head[u];i;i=edge[i].nex){
        int v=edge[i].v;
        if(vis[v]||v==fa) continue;
        getroot(v,u);
        sz[u]+=sz[v];
        mson[u]=max(mson[u],sz[v]);
    }
    mson[u]=max(mson[u],size-sz[u]);
    if(mson[u]<Min) Min=mson[u],root=u;
}

void getdis(int u,int fa,int len){
    ++mine[len];
    for(int i=head[u];i;i=edge[i].nex){
        int v=edge[i].v;
        if(vis[v]||v==fa) continue;
        getdis(v,u,len|a[v]);
    }
}

void change(int u,int fa,int len,int f){
    mine[len]+=f;
    for(int i=head[u];i;i=edge[i].nex){
        int v=edge[i].v;
        if(vis[v]||v==fa) continue;
        change(v,u,len|a[v],f);
    }
}

void dfs(int u,int fa,int len){
    for(int i=0;i<(1<<k);++i){
        if((i|len)!=flag) continue;
        if(!mine[i]) continue;
        ans+=mine[i];
    }
    for(int i=head[u];i;i=edge[i].nex){
        int v=edge[i].v;
        if(vis[v]||v==fa) continue;
        dfs(v,u,len|a[v]);
    }
}

void solve(int u){
    getdis(u,0,a[u]);
    for(int i=0;i<(1<<k);++i){
        if((i|a[u])!=flag) continue;
        if(!mine[i]) continue;
        ans+=mine[i];
    }
    for(int i=head[u];i;i=edge[i].nex){
        int v=edge[i].v;
        if(vis[v]) continue;
        change(v,u,a[u]|a[v],-1);
        dfs(v,u,a[u]|a[v]);
        change(v,u,a[u]|a[v],1);
    }
    memset(mine,0,sizeof(mine));
}

void fenzhi(int u,int ssize){
    vis[u]=1;
    solve(u);
    for(int i=head[u];i;i=edge[i].nex){
        int v=edge[i].v;
        if(vis[v]) continue;
        Min=inf,root=0;
        size=sz[v]<sz[u]?sz[v]:ssize-sz[u];
        getroot(v,0);
        fenzhi(root,size);
    }
}

int main(){
    while(~scanf("%d%d",&n,&k)){
        cnt=0;
        ans=0;
        flag=(1<<k)-1;
        for(int i=0;i<=n;++i)
            head[i]=vis[i]=0;
        memset(mine,0,sizeof(mine));
        for(int i=1;i<=n;++i){
            scanf("%d",&a[i]);
            a[i]=1<<(a[i]-1);
        }
        for(int i=1;i<n;++i){
            int u,v;
            scanf("%d%d",&u,&v);
            adde(u,v);
            adde(v,u);
        }
        Min=inf,root=0,size=n;
        getroot(1,0);
        fenzhi(root,n);
        printf("%lld\n",ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/FrankChen831X/p/11404151.html

时间: 2024-08-04 05:58:18

(模板)hdoj5977 Garden of Eden(点分治)的相关文章

hdu-5977 Garden of Eden(树分治)

题目链接: Garden of Eden Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 210    Accepted Submission(s): 75 Problem Description When God made the first man, he put him on a beautiful garden, the G

hdu 5977 Garden of Eden

Garden of Eden Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 581    Accepted Submission(s): 164 Problem Description When God made the first man, he put him on a beautiful garden, the Garden

P3810 【模板】三维偏序(陌上花开)

题目背景 这是一道模板题 可以使用bitset,CDQ分治,K-DTree等方式解决. 题目描述 有 nn 个元素,第 ii 个元素有 a_iai?.b_ibi?.c_ici? 三个属性,设 f(i)f(i) 表示满足 a_j \leq a_iaj?≤ai? 且 b_j \leq b_ibj?≤bi? 且 c_j \leq c_icj?≤ci? 的 jj 的数量. 对于 d \in [0, n)d∈[0,n),求 f(i) = df(i)=d 的数量 输入输出格式 输入格式: 第一行两个整数 n

编程题目分类(剪辑)

1. 编程入门 2. 数据结构 3. 字符串 4. 排序 5. 图遍历 6. 图算法 7. 搜索:剪枝,启发式搜索 8. 动态规划/递推 9. 分治/递归 10. 贪心 11. 模拟 12. 算术与代数 13. 组合问题 14. 数论 15. 网格,几何,计算几何 [编程入门] PC 110101, uva 100, The 3n+1 problem, 难度 1 PC 110102, uva 10189, Minesweeper, 难度 1 PC 110103, uva 10137, The T

POJ1741 Tree

本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/转载请注明出处,侵权必究,保留最终解释权! Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Define dist(u,v)=The min distan

UVA题目分类

题目 Volume 0. Getting Started 开始10055 - Hashmat the Brave Warrior 10071 - Back to High School Physics 10300 - Ecological Premium 458 - The Decoder 494 - Kindergarten Counting Game 414 - Machined Surfaces 490 - Rotating Sentences 445 - Marvelous Mazes

Fresh Bathroom Ideas

Feeling tired and powerless after a day’s work, you just want to take a bath and have a absolute relaxation to drive fatigue. Bathroom can be deemed as the secret garden of everyone, you can be the real you without any decorations and make-up there, 

计划,,留

下面给出的题目共计560道,去掉重复的也有近500题,作为ACMer Training Step1,用1年到1年半年时间完成.打牢基础,厚积薄发. 一.UVaOJ http://uva.onlinejudge.org 西班牙Valladolid大学的程序在线评测系统,是历史最悠久.最著名的OJ. 一.<算法竞赛入门经典> 刘汝佳 (UVaOJ 351道题) 以下部分内容摘自:http://sdkdacm.5d6d.com/thread-6-1-1.html "AOAPC I"

算法竞赛入门经典+挑战编程+USACO

下面给出的题目共计560道,去掉重复的也有近500题,作为ACMer Training Step1,用1年到1年半年时间完成.打牢基础,厚积薄发.   一.UVaOJ http://uva.onlinejudge.org  西班牙Valladolid大学的程序在线评测系统,是历史最悠久.最著名的OJ.   二.<算法竞赛入门经典> 刘汝佳  (UVaOJ  351道题)  以下部分内容摘自:http://sdkdacm.5d6d.com/thread-6-1-1.html   "AO