题目描述

When God made the first man, he put him on a beautiful garden, the Garden of Eden. Here Adam lived with all animals. God gave Adam eternal life. But Adam was lonely in the garden, so God made Eve. When Adam was asleep one night, God took a rib from him and made Eve beside him. God said to them, “here in the Garden, you can do everything, but you cannot eat apples from the tree of knowledge.”
One day, Satan came to the garden. He changed into a snake and went to live in the tree of knowledge. When Eve came near the tree someday, the snake called her. He gave her an apple and persuaded her to eat it. Eve took a bite, and then she took the apple to Adam. And Adam ate it, too. Finally, they were driven out by God and began a hard journey of life.
The above is the story we are familiar with. But we imagine that Satan love knowledge more than doing bad things. In Garden of Eden, the tree of knowledge has n apples, and there are k varieties of apples on the tree. Satan wants to eat all kinds of apple to gets all kinds of knowledge.So he chooses a starting point in the tree,and starts walking along the edges of tree,and finally stops at a point in the tree(starting point and end point may be same).The same point can only be passed once.He wants to know how many different kinds of schemes he can choose to eat all kinds of apple. Two schemes are different when their starting points are different or ending points are different.
Input
There are several cases.Process till end of input.
For each case, the first line contains two integers n and k, denoting the number of apples on the tree and number of kinds of apple on the tree respectively.
The second line contains n integers meaning the type of the i-th apple. Types are represented by integers between 1 and k .
Each of the following n-1 lines contains two integers u and v,meaning there is one edge between u and v.1≤n≤50000, 1≤k≤10
Output
For each case output your answer on a single line.
Sample Input
3 2
1 2 2
1 2
1 3
Sample Output
6

题目分析

鸡冻,终于自己完全独立地完成了一道树分治的题目啦。虽然还是调了三四个小时。。。

题目要求的是访问所有颜色的树上节点的方案数,而且必须是最短路径(不能重复访问节点保证的),因此我们联想到树分治。

不同于常见的树分治都是求树上路径如何,这里要求的是路径上点的状态要满足的条件。为了将问题转化我们将点的状态放在路径上,然后转化成树分治进行解决。现在问题转化成了如何表示树的状态。发现节点的颜色很少,我们可以用状态压缩,将颜色转化成二进制的位数,颜色为x,则对应的状态就是1<<(x-1),转化成数字一来方便表示,二来方便进行操作。

我们成功得到重心到所有点的状态后如何求满足条件的点对数呢?所谓满足条件,就是两个点所表示的状态进行位操作的或运算以后等于(1<<k)-1

那么我们如何快速得到任意两个点或运算以后等于(1<<k)-1的状态数呢?显然不能直接进行暴力。我们需要联想到FWT。

将每个状态数的点数存放在状态数组中,然后再对这个数组进行FWT,则Cnt[(1<<k)-1]中保存的就是答案。

其他的操作就是树分治的基本操作。

经验总结

虽然很快想到了思路,并且写出了代码,而且也可以通过样例,但是不知道为什么一直WA,而且很不自信,觉得自己写的思路可能有问题。在网上看其他人的代码他们好像都没有用到FWT,好像都是树形DP什么的,那个我还不会。但是又觉得自己的应该没有什么大问题。就很绝望。

睡了一晚起来再慢慢调试,一步一步地看,终于发现自己在一个很细小的地方犯了一个错误,虽然不知道为什么自己捏的各种各样的样例都能过,但是这个错误很根本。改了以后就过啦。

人呐,还是要自信一点,不要遇到错误就着急看别人怎么样。

AC代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<climits>
#include<algorithm>
#include<ctime>
#include<cstdlib>
#include<queue>
#include<set>
#include<map>
#include<cmath>using namespace std;
typedef long long ll;
const int MAXN=5e4+5;
struct edge
{int to,last;
}Edge[MAXN<<2]; int Last[MAXN],tot;
int n,kk,SonNum[MAXN],MaxNum[MAXN],Vis[MAXN],Record[MAXN],Color[MAXN];
int root,rootx,dlen,ss,len;
ll ans,Cnt[(1<<11)+100];
int Power[15];void FWT(ll *a,int N,int opt)
{for(int i=1;i<N;i<<=1)for(int p=i<<1,j=0;j<N;j+=p)for(int k=0;k<i;++k)/*or*/if(opt==1)a[i+j+k]=(a[j+k]+a[i+j+k]);else a[i+j+k]=(a[i+j+k]-a[j+k]);/*andif(opt==1)a[j+k]=(a[j+k]+a[i+j+k])%MOD;else a[j+k]=(a[j+k]+MOD-a[i+j+k])%MOD;*//*xor{int X=a[j+k],Y=a[i+j+k];a[j+k]=(X+Y)%MOD;a[i+j+k]=(X+MOD-Y)%MOD;//如果不是在模意义下的话,开一个long long,然后把逆元变成直接除二就好了if(opt==-1)a[j+k]=1ll*a[j+k]*inv%MOD,a[i+j+k]=1ll*a[i+j+k]*inv%MOD;}*/
}int getint()
{int x=0,sign=1; char c=getchar();while(c<'0' || c>'9'){if(c=='-') sign=-1; c=getchar();}while(c>='0' && c<='9'){x=x*10+c-'0'; c=getchar();}return x*sign;
}void Init()
{for(int i=0;i<=n;++i) Last[i]=0,Vis[i]=false;tot=0;
}void AddEdge(int u,int v)
{Edge[++tot].to=v; Edge[tot].last=Last[u]; Last[u]=tot;
}void Read()
{for(int i=1;i<=n;++i) Color[i]=getint()-1;int u,v,w;for(int i=1;i<n;i++){u=getint(); v=getint();AddEdge(u,v); AddEdge(v,u);}
}void GetRoot(int x,int father)
{int v;SonNum[x]=1; MaxNum[x]=1;for(int i=Last[x];i;i=Edge[i].last){v=Edge[i].to; if(v==father || Vis[v]) continue;GetRoot(v,x);SonNum[x]+=SonNum[v];if(SonNum[v]>MaxNum[x]) MaxNum[x]=SonNum[x];}MaxNum[x]=max(MaxNum[x],ss-SonNum[x]);if(rootx>MaxNum[x]) root=x,rootx=MaxNum[x];
}int Deal(int x,int now)
{return now|Power[Color[x]];
}void GetDis(int x,int father,int now)
{int t;t=Record[++dlen]=Deal(x,now);int v;for(int i=Last[x];i;i=Edge[i].last){v=Edge[i].to; if(v==father|| Vis[v]) continue;GetDis(v,x,t);}
}ll Count(int x,int now)
{for(int i=0;i<=dlen;++i) Record[i]=0;dlen=0;GetDis(x,0,now);memset(Cnt,0,sizeof(Cnt));for(int i=1;i<=dlen;++i)++Cnt[Record[i]];FWT(Cnt,len,1);for(int i=0;i<len;++i) Cnt[i]=Cnt[i]*Cnt[i];FWT(Cnt,len,-1);ll ret=Cnt[len-1];return ret;
}void Solve(int x)
{int v;ans+=Count(x,0);Vis[x]=true;for(int i=Last[x];i;i=Edge[i].last){v=Edge[i].to; if(Vis[v]) continue;ans-=Count(v,Deal(x,0));ss=SonNum[v]; rootx=INT_MAX; root=0;GetRoot(v,x);Solve(root);}
}void Work()
{if(kk==1) return;rootx=INT_MAX; ss=n; root=0; ans=0;len=1<<kk;GetRoot(1,0); Solve(root);
}void Write()
{if(kk==1) printf("%lld\n",(ll)n*n);else printf("%lld\n",ans);
}int main()
{for(int i=0;i<15;i++) Power[i]=1<<i;while(~scanf("%d%d",&n,&kk)){Init();Read();Work();Write();}return 0;
}

HDU5977-Garden of Eden-树分治+FWT相关推荐

  1. HDU5977 Garden of Eden 【FMT】【树形DP】

    题目大意:求有所有颜色的路径数. 题目分析: 参考codeforces997C,先利用基的FMT的性质在$O(2^k)$做FMT,再利用只还原一位的特点在$O(2^k)$还原,不知道为什么网上都要点分 ...

  2. 【HDU - 5977】Garden of Eden(树分治)

    题干: When God made the first man, he put him on a beautiful garden, the Garden of Eden. Here Adam liv ...

  3. 树的点分治(HDU 5977 2016ICPC大连 G: Garden of Eden)

    题意: 有一棵n个节点的数,每个点都有一个值(1<=pi<=k),问有多少条路径满足包含1到k中的所有数字 可以想到状压+树形dp,但是开dp[50005][1025]的数组内存占用过大, ...

  4. 【线段树分治 线性基】luoguP3733 [HAOI2017]八纵八横

    不知道为什么bzoj没有HAOI2017 题目描述 Anihc国有n个城市,这n个城市从1~n编号,1号城市为首都.城市间初始时有m条高速公路,每条高速公路都有一个非负整数的经济影响因子,每条高速公路 ...

  5. bzoj 4025 二分图——线段树分治+LCT

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4025 线段树分治,用 LCT 维护链的长度即可.不过很慢. 正常(更快)的方法应该是线段树分 ...

  6. 线段树分治 ---- F. Extending Set of Points(线段树分治 + 可撤销并查集)

    题目链接 题目大意: 你有个点集合SSS,每次往集合里面加点或者删点(如果要加的点出现过),如果(x1,y1),(x2,y1),(x1,y2),(x2,y2)(x1,y1),(x2,y1),(x1,y ...

  7. 线段树分治 ---- CF1217F - Forced Online Queries Problem(假离线 可撤销并查集 + 线段树分治)详解

    题目链接 题目大意 解题思路: 我一开始想到可以用可撤销并查集去维护这种删边加边的操作,但是有个缺点是每次撤销都有把后面的边全部撤销复度是O(n2)O(n^2)O(n2) 首先我们考虑这种动态加边删边 ...

  8. POJ 1741 树分治

    题目链接[http://poj.org/problem?id=1741] 题意: 给出一颗树,然后寻找点对(u,v)&&dis[u][v] < k的对数. 题解: 这是一个很经典 ...

  9. POJ1741:Tree——题解+树分治简要讲解

    http://poj.org/problem?id=1741 题目大意:给一棵树,求点对间距离<=k的个数. -------------------- 以这道题为例记录一下对于树分治的理解. 树 ...

最新文章

  1. Cisco Packet Tracer7.0的安装汉化与使用
  2. OpenCV 计算物体的凸包
  3. Android 可拖拽的GridView效果实现, 长按可拖拽和item实时交换
  4. ptrace 系统调用
  5. VS2008系列培训教程之四:What's new in C# 3.0 Visual Basic 9.0
  6. 数据拆分_数据拆分,偏方请拿好
  7. C语言字符输出格式化
  8. linux操作指令及根目录介绍
  9. htmlplay前端编辑器下载_2019年最好用的代码编辑器推荐
  10. 2019年3月23日
  11. SIP中第三方呼叫控制(3PCC)建立流程
  12. Excel中的数组函数
  13. 重学AS3之基础知识重点记忆
  14. 基于Python深度学习的DGA域名检测
  15. Arx常用代码《转》
  16. Linux配置Samba在局域网共享文件
  17. HTML空白字符占位问题
  18. Python画好看的星空图
  19. Warframe Rank考核
  20. 前阿里P8甩我一份内部SpringCloud笔记手册,真香

热门文章

  1. 洛谷 2719 搞笑世界杯
  2. BZOJ.1023.[SHOI2008]cactus仙人掌图(DP)
  3. SQL数据库中临时表、临时变量和WITH AS关键词创建“临时表”的区别
  4. javascript事件与event对象的属性
  5. C# 方法返回值的个数
  6. Android下拉刷新完全解析,教你如何一分钟实现下拉刷新功能 (转)
  7. 金蝶Apusic应用服务器的数据源管理(转)
  8. java取非_java运算符 与()、非(~)、或(|)、异或(^)
  9. iis7.5配置php环境,iis7.5安装配置php环境 - iis
  10. linux服务器基本常识,服务器搭建-Linux基础知识