HDU5977 Garden of Eden 树分治+高维前缀和
来源:互联网 发布:touch bar 知乎 编辑:程序博客网 时间:2024/06/05 16:57
题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5977
题意:给一个有n(1<=n<=5e4)个节点的树,每个节点有一个颜色,共有k(1<=k<=7)种不同的颜色,问有多少个点对(u,v)(注意(u,v)和(v,u)算作两个答案),这些点对之间的路径上有k个不同的颜色。
解法:树分治+高维前缀和,暴力枚举就超时了,但是只要知道高维前缀和以及枚举子集的相关知识,就能用O(k*(1<<k))结束统计,外面套上树分治,O(n*logn+n*k*(1<<k) )的时间。树分治还是那样的树分治,用状态压缩记录路径上遇到的点,接着用高维前缀和统计每个状态和他们的超集的个数,一次分治的计数方法就是num[i]*cnt[i^(1<<k-1)],num[i]记录的是状态i的出现次数,cnt[i]是状态i和i超集的总个数,统计每个i。高维前缀和是一种计数方法,只是短短的几行,用来计算包含i的集合的总个数。其他部分应该都ok。
//高维前缀和+树分治#include <bits/stdc++.h>using namespace std;typedef long long LL;const int maxn = 1e5+10;const int maxm = 2e5+10;struct edge{ int v,next,w;}E[maxm];int head[maxn],edgecnt;int n,vis[maxn],root;LL ans;void init(){ memset(head,-1,sizeof(head)); memset(vis,0,sizeof(vis)); edgecnt=ans=0;}void add(int u,int v){ E[edgecnt].v = v, E[edgecnt].next = head[u],head[u] = edgecnt++;}int mx[maxn],siz[maxn],col[maxn],mi,K,k;LL cnt[maxn], cnt1[maxn];void dfssize(int u, int fa){//处理子树的大小 siz[u]=1; mx[u]=0; for(int i=head[u];~i;i=E[i].next){ int v=E[i].v; if(v!=fa&&!vis[v]){ dfssize(v, u); siz[u]+=siz[v]; if(siz[v]>mx[u]) mx[u]=siz[v]; } }}void dfsroot(int r, int u, int fa){//求重心 if(siz[r]-siz[u]>mx[u]) mx[u]=siz[r]-siz[u]; if(mx[u]<mi) mi=mx[u],root=u; for(int i=head[u]; ~i; i=E[i].next){ int v=E[i].v; if(v!=fa&&!vis[v]) dfsroot(r, v, u); }}void dfs(int u, int fa, int sta){ sta |= (1<<col[u]); ++cnt[sta]; ++cnt1[sta]; for(int i=head[u]; ~i; i=E[i].next){ int v = E[i].v; if(!vis[v]&&v!=fa) dfs(v, u, sta); }}LL cal(int u, int sta){ for(int i=0; i<=K; i++) cnt[i]=cnt1[i]=0; sta |= (1<<col[u]); ++cnt[sta]; ++cnt1[sta]; for(int i=head[u]; ~i; i=E[i].next){ int v = E[i].v; if(!vis[v]) dfs(v, u, sta); } for(int i=0; i<k; i++) for(int j=0; j<K; j++) if(!(j&(1<<i))) cnt[j] += cnt[j|(1<<i)]; LL ret = 0; for(int i=1; i<=K; i++) ret += cnt1[i]*cnt[(K^i)]; return ret;}void DFS(int u){ mi = n; dfssize(u, 0); dfsroot(u, u, 0); u = root; ans += cal(root, 0); vis[root] = 1; for(int i=head[root]; ~i; i=E[i].next){ int v = E[i].v; if(!vis[v]){ ans -= cal(v, (1<<col[u])); DFS(v); } }}int main(){ while(~scanf("%d%d", &n,&k)){ K = (1<<k)-1; init(); for(int i=1; i<=n; i++) scanf("%d", &col[i]), col[i]--; for(int i=1; i<n; i++){ int u, v; scanf("%d %d", &u,&v); add(u, v); add(v, u); } DFS(1); printf("%lld\n", ans); } return 0;}
阅读全文
0 0
- HDU5977 Garden of Eden 树分治+高维前缀和
- HDU5977 Garden of Eden 树分治+高维前缀和
- hdu 5977 Garden of Eden(树分治+高维前缀和)
- hdu5977 Garden of Eden
- hdu5977 Garden of Eden
- HDU5977-Garden of Eden
- hdu-5977 Garden of Eden(树分治)
- HDU 5977 Garden of Eden(树分治)
- HDU-5977 Garden of Eden(树分治+枚举子集)
- 文章标题 HDU 5977 : Garden of Eden (树分治)
- 树的点分治(HDU 5977 && 2016ICPC大连 G: Garden of Eden)
- Uva10001 Garden of Eden
- 10001 - Garden of Eden
- uva10001 - Garden of Eden
- uva10001 Garden of Eden
- hdu5977 树分治
- UVa 10001 - Garden of Eden
- UVA 10001 Garden of Eden
- UVA 469 Wetlands of Florida
- static和extern对函数的作用
- 机器学习第3章第5节 : 调整图像亮度
- 哈希查找
- Oracle 使用技巧
- HDU5977 Garden of Eden 树分治+高维前缀和
- Swift开发指南:使用Swift与Cocoa和Objective-C(Swift 4)
- Codeforces Round #437 (Div. 2, based on MemSQL Start[c]UP 3.0
- 2015-2016 ACM-ICPC, NEERC, Northern Subregional Contest【9/12】
- 机器学习笔记--K近邻
- 第四周项目5-猴子选大王
- 用opencv将物体框出
- 二叉树
- Java300StudyNote(9)-unicode和GBK,UTF-8,UTF-16,图解各种字符集之间的关系、Java内部使用的字符集、字符集的兼容性问题、乱码问题