题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5977

题解:这题一看就知道是状压dp然后看了一下很像是点分治(有点明显)然后就是简单的点分治+状压dp,这里只要稍微改一下模版就行了。还有注意一下这里的cau状态枚举然后就没什么了

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
const int M = 5e4 + ;
struct Edge {
int v , next;
}edge[M << ];
int head[M] , e , Size , root , n , k , a[M] , ssr;
ll ans;
bool vis[M];
void init() {
memset(head , - , sizeof(head));
memset(vis , false , sizeof(vis));
ans = ;
e = ;
ssr = (( << k) - );
}
void add(int u , int v) {
edge[e].v = v;
edge[e].next = head[u];
head[u] = e++;
}
int size[M] , mx[M];
ll Hash[];
void dfs_size(int u , int pre) {
size[u] = ;
mx[u] = ;
for(int i = head[u] ; i != - ; i = edge[i].next) {
int v = edge[i].v;
if(v == pre || vis[v]) continue;
dfs_size(v , u);
size[u] += size[v];
mx[u] = max(mx[u] , size[v]);
}
}
void dfs_root(int r , int u , int pre) {
mx[u] = max(mx[u] , size[r] - size[u]);
if(mx[u] < Size) Size = mx[u] , root = u;
for(int i = head[u] ; i != - ; i = edge[i].next) {
int v = edge[i].v;
if(v == pre || vis[v]) continue;
dfs_root(r , v , u);
}
}
void get_root(int u , int pre) {
dfs_size(u , pre);
dfs_root(u , u , pre);
}
int num , State[M];
void find_state(int u , int pre , int state) {
State[num++] = state;
for(int i = head[u] ; i != - ; i = edge[i].next) {
int v = edge[i].v;
if(vis[v] || v == pre) continue;
find_state(v , u , state | ( << a[v]));
}
}
ll cau(int u , int state) {
num = ;
find_state(u , - , state);
memset(Hash , , sizeof(Hash));
ll sum = ;
for(int i = ; i < num ; i++) Hash[State[i]]++;
for(int i = ; i < num ; i++) {
Hash[State[i]]--;
sum += Hash[ssr];//这里由于是枚举时0枚举不到所以先加上ssr^0.
for (int s0 = State[i]; s0; s0 = (s0 - ) & State[i])
sum += Hash[(( << k) - ) ^ s0];
Hash[State[i]]++;
}
return sum;
}
void dfs(int u) {
Size = n;
get_root(u , -);
ans += cau(root , ( << a[root]));
vis[root] = true;
int rt = root;
for(int i = head[root] ; ~i ; i = edge[i].next) {
int v = edge[i].v;
if(vis[v]) continue;
ans -= cau(v , ( << a[rt]) | ( << a[v]));
dfs(v);
}
}
int main() {
while(scanf("%d%d" , &n , &k) != EOF) {
init();
for(int i = ; i <= n ; i++) scanf("%d" , &a[i]) , a[i]--;
for(int i = ; i < n - ; i++) {
int u , v;
scanf("%d%d" , &u , &v);
add(u , v);
add(v , u);
}
if (k == ) {
printf("%lld\n", (ll)n * (ll)n);
continue;
}
dfs();
printf("%lld\n" , ans);
}
return ;
}

最新文章

  1. OpenSessionInView模式
  2. MyBatis学习--逆向工程
  3. 数字信号处理实验(六)&mdash;&mdash;FIR滤波器的设计
  4. Node.js 手册查询-3-Mongoose 方法
  5. 本机搭建外网web服务器
  6. 线上Linux服务器运维安全策略经验分享
  7. java学习面向对象之继承
  8. Wi-Fi漫游的工作原理
  9. 排序算法c语言描述---选择排序
  10. tomcat 修改端口(Java之负基础实战)
  11. 菜鸟的java代码审计之旅-0之java基础知识
  12. 好用的6个css方法
  13. eclipse如何加入第三方jar包
  14. Java中关键字this、super的含义及使用
  15. 常用的jquerymobil 站点
  16. easyui 获取特定页签tab
  17. rpm -qa 查找文件
  18. input 内容改变的触发事件
  19. Python raw_input和input总结 在版本2和版本3中的区别
  20. log4net配置详细说明

热门文章

  1. 深入理解Java中的AQS
  2. java多线程核心api以及相关概念(一)
  3. TCP queue 的一些问题
  4. js实现3D切换效果
  5. ASP.NET Core - 实现自定义WebApi模型验证
  6. poj 1050 To the Max(最大子矩阵之和)
  7. Hexo结合github制作博客
  8. DesignPattern系列__03依赖倒置原则
  9. LeetCode刷题总结之双指针法
  10. springmvc异步处理