题目链接: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 ;
}

最新文章

  1. MongoDB系列(二):C#应用
  2. ubuntu14.04为安装fcitx卸载ibus后出现system setting (系统设置)中图标消失的问题
  3. Spring MVC之cookies跟session 数据绑定
  4. spring中context:property-placeholder/元素
  5. 手机CPU知识扫盲:谈谈手机CPU架构与原理 (全
  6. 【解题报告】POJ-1467 Symbolic Derivation
  7. 代理和 block 传值的使用
  8. poj 1132
  9. February 29(模拟)
  10. jmeter java请求
  11. 创建 Mac OS X 10.9 USB 安装盘
  12. jps 命令使用
  13. 微信小程序基本组件概述
  14. NodeJs之EXCEL文件导入导出MongoDB数据库数据
  15. Selenium+TestNG+Maven+Jenkins+SVN(转载)
  16. 拓展中国剩余定理(ex_crt)
  17. Lintcode97-Maximum Depth of Binary Tree-Easy
  18. canvas动画效果新年祝福话语
  19. 查看进程:ps
  20. py库: jieba (中文词频统计) 、collections (字频统计)、WordCloud (词云)

热门文章

  1. maven工程指定jdk版本,maven全局配置jdk的版本
  2. MFC 标签页Tab Control
  3. Luogu P1903 [国家集训队]数颜色 or 维护队列
  4. 如何在 Laravel 中灵活的使用 Trait
  5. c++ const修饰词
  6. 期望与概率dp
  7. 「BZOJ 1698」「USACO 2007 Feb」Lilypad Pond 荷叶池塘「最短路」
  8. TCO14 Wildcard CountTables——斯特林反演
  9. html,css,js实现的一个钟表
  10. 【零基础】Selenium:Webdriver图文入门教程java篇(附相关包下载)