题目链接: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=;
const int inf=0x3f3f3f3f;
struct node{
int v,nex;
}edge[maxn<<]; int n,k,cnt,head[maxn],a[maxn],sz[maxn],mson[maxn],Min,size,root;
int vis[maxn],flag;
LL ans,mine[]; 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]=,mson[u]=;
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=;i<(<<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,,a[u]);
for(int i=;i<(<<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],-);
dfs(v,u,a[u]|a[v]);
change(v,u,a[u]|a[v],);
}
memset(mine,,sizeof(mine));
} void fenzhi(int u,int ssize){
vis[u]=;
solve(u);
for(int i=head[u];i;i=edge[i].nex){
int v=edge[i].v;
if(vis[v]) continue;
Min=inf,root=;
size=sz[v]<sz[u]?sz[v]:ssize-sz[u];
getroot(v,);
fenzhi(root,size);
}
} int main(){
while(~scanf("%d%d",&n,&k)){
cnt=;
ans=;
flag=(<<k)-;
for(int i=;i<=n;++i)
head[i]=vis[i]=;
memset(mine,,sizeof(mine));
for(int i=;i<=n;++i){
scanf("%d",&a[i]);
a[i]=<<(a[i]-);
}
for(int i=;i<n;++i){
int u,v;
scanf("%d%d",&u,&v);
adde(u,v);
adde(v,u);
}
Min=inf,root=,size=n;
getroot(,);
fenzhi(root,n);
printf("%lld\n",ans);
}
return ;
}

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

  1. hdu-5977 Garden of Eden(树分治)

    题目链接: Garden of Eden Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/ ...

  2. HDU 5977 Garden of Eden(点分治求点对路径颜色数为K)

    Problem Description When God made the first man, he put him on a beautiful garden, the Garden of Ede ...

  3. HDU 5977 Garden of Eden (树分治+状态压缩)

    题意:给一棵节点数为n,节点种类为k的无根树,问其中有多少种不同的简单路径,可以满足路径上经过所有k种类型的点? 析:对于路径,就是两类,第一种情况,就是跨过根结点,第二种是不跨过根结点,分别讨论就好 ...

  4. HDU-5977 - Garden of Eden 点分治

    HDU - 5977 题意: 给定一颗树,问树上有多少节点对,节点对间包括了所有K种苹果. 思路: 点分治,对于每个节点记录从根节点到这个节点包含的所有情况,类似状压,因为K<=10.然后处理每 ...

  5. HDU5977 Garden of Eden(树的点分治)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5977 Description When God made the first man, he ...

  6. Garden of Eden

    Garden of Eden Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others ...

  7. uva10001 Garden of Eden

    Cellular automata are mathematical idealizations of physical systems in which both space and time ar ...

  8. (模板)luoguP3806(树上点分治模板题)

    点分治的写法1: 题目链接:https://www.luogu.org/problem/P3806 题意:给出一颗带边权的树,结点数n<=1e4,每条边有权值<=1e4,有m组询问(m&l ...

  9. 洛谷P4719 【模板】"动态 DP"&动态树分治

    [模板]"动态 DP"&动态树分治 第一道动态\(DP\)的题,只会用树剖来做,全局平衡二叉树什么的就以后再学吧 所谓动态\(DP\),就是在原本的\(DP\)求解的问题上 ...

随机推荐

  1. learning gcc __BEGIN_DECLS and __END_DECLS

    __BEGIN_DECLS and  __END_DECLS  be use for mix C and C++

  2. 获取link后的参数值

    getQueryString:function(name){ var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i ...

  3. 收藏一个RMQ模板

    int a[1100]; int dp[maxn][20]; void rmq_init(){ for(int i=0;i<n;i++) dp[i][0]=a[i]; for(int j=1;( ...

  4. 利用Python脚本完成一个Fat-tree型的拓扑

    利用Python脚本完成如下图所示的一个Fat-tree型的拓扑(交换机和主机名需与图中一致,即s1~s6,h1~h8) 参考资料 修改代码如下: from mininet.topo import T ...

  5. Mysql索引查询失效的情况

    首先,复习一下索引的创建: 普通的索引的创建: CREATE INDEX  (自定义)索引名  ON  数据表(字段); 复合索引的创建: CREATE INDEX  (自定义)索引名  ON  数据 ...

  6. Leetcode题目101.对称二叉树(简单)

    题目描述: 给定一个二叉树,检查它是否是镜像对称的. 例如,二叉树 [1,2,2,3,4,4,3] 是对称的. 1 / \ 2 2 / \ / \ 3 4 4 3 但是下面这个 [1,2,2,null ...

  7. 2018-2019-2 20165330《网络对抗技术》Exp7 网络欺诈防范

    目录 基础问题 相关知识 实验目的 实验内容 实验步骤 实验中遇到的问题 实验总结与体会 实验目的 本实践的目标理解常用网络欺诈背后的原理,以提高防范意识,并提出具体防范方法. 返回目录 实验内容 简 ...

  8. Nginx之编写HTTP模块

    1. 常用数据结构 1.1 ngx_str_t typedef struct { /* * 字符串的有效长度 */ size_t len; /* * 有效字符串的起始地址,该字符串通常并不以'\0'结 ...

  9. cannot open clipboard 解决办法

    对于电脑本身或者一些应用程序操作的时候,会出现cannot open clipboard的问题,这是你系统没有剪切板程序 首先: 在开始->运行中输入clipbrd 回车, 如果系统弹出了剪切板 ...

  10. 【VMWare】虚拟机启动遇到黑屏,在命令行窗口输入netsh winsock reset并不管用 重新启动客户机就好了

    现象:虚拟机启动后是莫名其妙的黑屏,而且它上面安装的MySql也无法访问了. 处置:上网百度方案,看到大多数网文推荐:“以管理员身份打开cmd,输入netsh winsock reset,然后重启机器 ...