思路:首先当然是要用树的点分治了。根节点为root,那么经过root的合法路径数求出来这题就解决了。因为我们可以用分治枚举根,最后将所有根的路径数加起来就是结果。当然这里的根不是整棵树的根,是子树根。

我们为每个节点分配一个长度为30的数组记录给定因数在每个节点权值出现的次数。如果某几个权值相乘的值Value的三次根仍是整数的话,那么Value在给定因数的所有幂一定是3的倍数。通过这个转换,我们将所有的幂都对3取余,结果还是一样。

在判断经过root的合法路径数时,我们进入其一个子树,将经过的路径因数的幂相加,判读其是否有对立状态存在,若存在,结果+1。所谓对立状态就是能够合成合法路径的状态。

例如因数为 2,3,5.

那么 x节点的状态为 0,1,2 表示2的0次幂,3的1次幂,5的2次幂。

其对立状态就是 0,2,1。因为他这两条路径合成一条后,就变成了0,3,3.都是3的倍数。

状态数的记录,我们可以用long long 型的map。

要加栈,不然会RE。我就连续两次RE,加了就AC了。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<vector>
#include<map>
#define Maxn 100010
#define Maxm 200010
#define LL __int64
#define inf 0x7fffffff
using namespace std;
map<LL,LL> hash;
int head[Maxn],vi[Maxn],e,ans,num,k,n,m,prime[],lans;
int mx[Maxn],mi,dis[Maxn],root,size[Maxn];
LL Exp[];
struct Node{
int cnt[];
}node[Maxn];
struct Edge{
int u,v,val,next;
}edge[Maxm];
vector <Node> q;
void init()
{
memset(vi,,sizeof(vi));
memset(head,-,sizeof(head));
memset(mx,,sizeof(mx));
memset(dis,,sizeof(dis));
q.clear();
hash.clear();
Exp[]=;
for(int i=;i<=;i++)
Exp[i]=Exp[i-]*;
e=ans=lans=;
}
void add(int u,int v)
{
edge[e].u=u,edge[e].v=v,edge[e].next=head[u],head[u]=e++;
edge[e].u=v,edge[e].v=u,edge[e].next=head[v],head[v]=e++;
}
void dfssize(int u,int fa)
{
int i,v;
size[u]=;
mx[u]=;
for(i=head[u];i!=-;i=edge[i].next)
{
v=edge[i].v;
if(v!=fa&&!vi[v])
{
dfssize(v,u);
size[u]+=size[v];
if(size[v]>mx[u]) mx[u]=size[v];
}
}
}
void dfsroot(int r,int u,int fa)
{
int v,i;
if(size[r]-size[u]>mx[u]) mx[u]=size[r]-size[u];
if(mx[u]<mi) mi=mx[u],root=u;
for(i=head[u];i!=-;i=edge[i].next)
{
v=edge[i].v;
if(v!=fa&&!vi[v])
{
dfsroot(r,v,u);
}
}
}
void dfsdis(int u,Node d,int fa)
{
int i,v,j;
q.push_back(d);
LL cc=;
for(j=;j<=k;j++)//判断其是否存在对立状态
{
cc+=(-(d.cnt[j]+node[root].cnt[j])%)%*Exp[j];
}
lans+=hash[cc];//答案加上对立状态数
Node temp;
for(i=head[u];i!=-;i=edge[i].next)
{
v=edge[i].v;
if(v!=fa&&!vi[v])
{
for(j=;j<=k;j++)
{
temp.cnt[j]=(d.cnt[j]+node[v].cnt[j])%;
}
dfsdis(v,temp,u);
}
}
}
int calc(int u)
{
int i,j,ret=,sz,v;
lans=;
hash.clear();
hash[]=;
for(i=head[u];i!=-;i=edge[i].next)
{
q.clear();
v=edge[i].v;
if(!vi[v])
{
dfsdis(v,node[v],u);
sz=q.size();
//cout<<u<<" "<<v<<" "<<sz<<endl;
for(int r=;r<sz;r++)//回退时,记录这条子路径上的所有状态数。
{
LL cc=;
for(j=;j<=k;j++)
{
cc+=q[r].cnt[j]*Exp[j];
}
hash[cc]++;
}
}
}
return lans;
}
void dfs(int u)
{
int i,v,j;
mi=n;
dfssize(u,);
dfsroot(u,u,);
ans+=calc(root);
//cout<<root<<"************"<<endl;
vi[root]=;
for(i=head[root];i!=-;i=edge[i].next)
{
v=edge[i].v;
if(!vi[v])
{
dfs(v);
}
}
}
int main()
{
int i,j,u,v;
LL x;
while(scanf("%d",&n)!=EOF)
{
init();
scanf("%d",&k);
for(i=;i<=k;i++)
scanf("%d",&prime[i]);
for(i=;i<=n;i++)
{
scanf("%I64d",&x);
memset(node[i].cnt,,sizeof(node[i].cnt));
for(j=;j<=k;j++)
{
while(x%prime[j]==&&x!=)
{
node[i].cnt[j]++;
node[i].cnt[j]%=;
x/=prime[j];
}
if(x==)
break;
}
int cc=;
for(j=;j<=k;j++)
cc+=node[i].cnt[j];
if(cc==)
ans++;
}
//printf("&&&&&&&&&&&&\n");
for(i=;i<n;i++)
{
scanf("%d%d",&u,&v);
add(u,v);
}
dfs();
printf("%d\n",ans);
}
return ;
}

hdu 4670 树的点分治的更多相关文章

  1. hdu 4670 树的分治-求点对的个数

    /* 树的分治 因为树的点权值可达到10^15,注意手动扩栈,还有int64 题意:给你一棵树,给你一些素数,给你每个点一个权值且每个权值均可由这些素数组成.现在定义任意任意两点的价值为他们路径上的权 ...

  2. hdu 4670 Cube number on a tree(点分治)

    Cube number on a tree Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/ ...

  3. hdu 4812 D Tree(树的点分治)

    D Tree Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others) Total ...

  4. HDU4812 D Tree(树的点分治)

    题目大概说给一棵有点权的树,输出字典序最小的点对,使这两点间路径上点权的乘积模1000003的结果为k. 树的点分治搞了.因为是点权过根的两条路径的LCA会被重复统计,而注意到1000003是质数,所 ...

  5. CF 322E - Ciel the Commander 树的点分治

    树链剖分可以看成是树的边分治,什么是点分治呢? CF322E - Ciel the Commander 题目:给出一棵树,对于每个节点有一个等级(A-Z,A最高),如果两个不同的节点有相同等级的父节点 ...

  6. bzoj 3435: [Wc2014]紫荆花之恋 替罪羊树维护点分治 && AC400

    3435: [Wc2014]紫荆花之恋 Time Limit: 240 Sec  Memory Limit: 512 MBSubmit: 159  Solved: 40[Submit][Status] ...

  7. bzoj 2152: 聪聪可可 树的点分治

    2152: 聪聪可可 Time Limit: 3 Sec  Memory Limit: 259 MBSubmit: 485  Solved: 251[Submit][Status] Descripti ...

  8. hdu 3842 Machine Works(cdq分治维护凸壳)

    题目链接:hdu 3842 Machine Works 详细题解: HDU 3842 Machine Works cdq分治 斜率优化 细节比较多,好好体会一下. 在维护斜率的时候要考虑x1与x2是否 ...

  9. hdu_5314_Happy King(树的点分治)

    题目链接:hdu_5314_Happy King 题意: 给出一颗n个结点的树,点上有权值: 求点对(x,y)满足x!=y且x到y的路径上最大值与最小值的差<=D: 题解: 还是树的点分治,在统 ...

随机推荐

  1. Struts2的运行流程以及关键拦截器介绍

    Struts2的运行流程 1.ActionProxy是Action的一个代理类,也就是说Action的调用是通过ActionProxy实现的,其实就是调用了ActionProxy.execute()方 ...

  2. poj 1543 Perfect Cubes(注意剪枝)

    Perfect Cubes Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 14901   Accepted: 7804 De ...

  3. ASP.NET中身份验证的三种方法

    Asp.net的身份验证有有三种,分别是"Windows | Forms | Passport",其中又以Forms验证用的最多,也最灵活.Forms 验证方式对基于用户的验证授权 ...

  4. Codeforces Round #116 (Div. 2, ACM-ICPC Rules) E. Cubes (尺取)

    题目链接:http://codeforces.com/problemset/problem/180/E 给你n个数,每个数代表一种颜色,给你1到m的m种颜色.最多可以删k个数,问你最长连续相同颜色的序 ...

  5. 三,对于printf函数和C语言编程的初步拓展

    前面说过了,任何程序都要有输出,所以printf函数是一个很重要的函数,所以有必要在学变量之前先拓展一下. 其实编程就是用计算机语言说话,一句一句地说,只要语法没错就能运行,至于能实现什么功能,就看编 ...

  6. Spring-AOP和AspectJ的区别和联系

    AOP是Spring框架的重要组成部分.目前我所接触的AOP实现框架有Spring AOP还有就是AspectJ(还有另外几种我没有接触过).我们先来说说他们的区别: AspectJ是一个比较牛逼的A ...

  7. SAP CRM 最新简介文字(2007年、中英文)

    以下内容是SAP CRM功能的精简描述,摘自SAP官方文档,附上中英文版本,可以对SAP CRM的主要功能有大致了解. 营销 - 使用营销资源管理.客户细分及列表管理.营销活动管理.线索管理.贸易促销 ...

  8. utf-8 和gbk编码的差别

    UTF- 8: 是用以解决国际上字符的一种多字节编码,它对英文使用8位(即一个字节),中文使用24为(三个字节)来编码. GBK 是国家标准GB2312基础上扩容后兼容GB2312的标准. GBK的文 ...

  9. Windows下载Android源代码

    下载msysgit,安装 官方下载:http://code.google.com/p/msysgit/downloads/list, 打开Git Bash,运行命令 cd D: git clone h ...

  10. uva216 c++回溯法

    因为题目要求最多8台电脑,所以可以枚举全排列,然后依次计算距离进行比较,枚举量8!=40320并不大,但这种方法不如回溯法好,当数据再大一些枚举就显得笨拙了,所以这个题我用回溯法做的,回溯有一个好处是 ...