The country Tom living in is famous for traveling. Every year, many tourists from all over the world have interests in traveling there. 
There are n provinces in the country. According to the experiences from the tourists came before, every province has its own preference value. A route’s preference value from one province to another is defined as the product of all the preference value of the provinces on the route. It’s guaranteed that for each two provinces in the country there is a unique route from one to another without passing any province twice or more. 
Tom is a boy crazy about cube number. A cube number is a positive integer whose cube root is also an integer. He is planning to travel from a province to another in the summer vacation and he will only choose the route with the cube number preference value. Now he want to know the number of routes that satisfy his strange requirement.

Input

The input contains several test cases, terminated by EOF. 
Each case begins with a number n ( 1 ≤ n ≤ 50000), the number of the provinces. 
The second line begins with a number K (1 ≤ K ≤ 30), and K difference prime numbers follow. It’s guaranteed that all the preference number can be represented by the product of some of this K numbers(a number can appear multiple times). 
The third line consists of n integer numbers, the ith number indicating the preference value P i(0 ≤ P i ≤ 10 15) of the i-th province. 
Then n - 1 lines follow. Each line consists of two integers x, y, indicating there is a road connecting province x and province y.

Output

For each test case, print a number indicating the number of routes that satisfy the requirement.Sample Input

5
3 2 3 5
2500 200 9 270000 27
4 2
3 5
2 5
4 1

Sample Output

1

题解:

题意:给你一棵树,给你一些素数,给你每个点一个权值且每个权值均可由这些素数组成。现在定义任意任意两点的价值为他们路径上的权值相乘。求这样的点对的权值为立方数的个数
如果直接求得话会超int64,不可行
由立方数的性质可得,一个数可有素数组成,对于这些素数可以分解为这些素数相乘的形式如,24=(2^3)*(3^1);如果是立方数的话那么他的各进制对3取余都为0.股24可写成01这种三进制形式
对于这些权值的乘法可有三进制想加可得。
接下来就是树的分治了
当然这里可以先求出一条子树上的各个点的权值乘积,然后和根节点和其他字树比较看是否可以互补那么就找到一对
可用map容器实现。因为他重点是比较到根节点和其他子树是否可以互补,进而递归下去,求出每个子树的这样的点对

参考代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define fi first
#define se second
#define pii pair<int,int>
#define pil pair<int,ll>
#define mkp make_pair
#define pb push_back
const int INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f3f3f3f3fll;
inline ll read()
{
ll x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-') f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=(x<<)+(x<<)+ch-'';ch=getchar();}
return x*f;
}
const int maxn=1e5+;
ll n,k,head[maxn],tot,root,siz[maxn];
ll h[maxn][],pri[],fa[maxn],mx[maxn],S;
ll dep,ch[maxn][],fp[maxn],minn,nn;
bool vis[maxn];
map<ll,ll> mp;
struct Edge{
int v,nxt;
} edge[maxn<<]; inline void Init()
{
tot=;
memset(head,-,sizeof(head));
memset(h,,sizeof(h));
memset(mx,,sizeof(mx));
memset(siz,,sizeof(siz));
memset(vis,false,sizeof(vis));
} inline void AddEdge(ll u,ll v)
{
edge[tot].v=v;
edge[tot].nxt=head[u];
head[u]=tot++;
} inline void dfs1(ll u,ll fa)
{
nn++;
for(int e=head[u];~e;e=edge[e].nxt)
{
ll v=edge[e].v;
if(v==fa||vis[v]) continue;
dfs1(v,u);
}
} inline void GetRoot(ll u,ll fa)
{
siz[u]=;
ll tit=;
for(ll e=head[u];~e;e=edge[e].nxt)
{
ll v=edge[e].v;
if(v==fa||vis[v]) continue;
GetRoot(v,u);
siz[u]+=siz[v];
tit=max(tit,siz[v]);
}
tit=max(tit,nn-siz[u]);
if(tit<minn) minn=tit,root=u;
}
inline void dfs2(ll u,ll fa)
{
//cout<<"dfs2"<<endl;
if(fa==-)
{
for(ll i=;i<=k;++i)
ch[dep][i]=h[u][i];
}
else
{
ll e=fp[fa];
for(ll i=;i<=k;++i)
ch[dep][i]=(h[u][i]+ch[e][i])%;
}
fp[u]=dep++;
for(ll e=head[u];~e;e=edge[e].nxt)
{
ll v=edge[e].v;
if(v!=fa&&!vis[v]) dfs2(v,u);
}
} inline ll work(ll u)
{
ll s1=,ans=;
mp.clear();
for(ll i=;i<=k;++i) s1=s1*+h[u][i];
if(s1==) ans++;
mp[s1]=;
for(ll e=head[u];~e;e=edge[e].nxt)
{
ll v=edge[e].v;
if(vis[v]) continue;
dep=;dfs2(v,-);
for(ll i=;i<dep;++i)
{
s1=;
for(ll j=;j<=k;++j)
s1=s1*+(-ch[i][j])%;
ans+=mp[s1];
}
for(ll i=;i<dep;++i)
{
s1=;
for(ll j=;j<=k;++j)
s1=s1*+(ch[i][j]+h[u][j])%;
mp[s1]++;
}
}
return ans;
} inline ll dfs(ll u)
{
nn=,minn=inf;
dfs1(u,-);
GetRoot(u,-);
vis[root]=;
ll ans=work(root);
for(ll e=head[root];~e;e=edge[e].nxt)
{
ll v=edge[e].v;
if(vis[v]) continue;
ans+=dfs(v);
}
return ans;
} int main()
{
while(~scanf("%lld",&n))
{
Init();
k=read();
for(ll i=;i<=k;++i) pri[i]=read(); for(ll i=;i<=n;++i)
{
ll kk,val=read();
for(ll j=;j<=k;++j)
{
kk=;
while(val%pri[j]==)
{
++kk;
val/=pri[j];
kk%=;
}
h[i][j]=kk;
}
}
for(ll i=;i<n;++i)
{
ll x,y;
x=read();y=read();
AddEdge(x,y);AddEdge(y,x);
}
//cout<<"1"<<endl;
printf("%lld\n",dfs());
} return ;
}

HDU4670 cube number on a tree(点分治+三进制加法)的更多相关文章

  1. HDU4670 Cube number on a tree 树分治

    人生的第一道树分治,要是早点学我南京赛就不用那么挫了,树分治的思路其实很简单,就是对子树找到一个重心(Centroid),实现重心分解,然后递归的解决分开后的树的子问题,关键是合并,当要合并跨过重心的 ...

  2. [hdu4670 Cube number on a tree]点分治

    题意:给一个N个带权节点的树,权值以给定的K个素数为因子,求路径上节点乘积为立方数的路径条数 思路:立方数的性质是每个因子的个数为3的倍数,那么每个因子只需要保存0-2三个状态即可,然后路径就可以转化 ...

  3. 【点分治】【map】【哈希表】hdu4670 Cube number on a tree

    求树上点权积为立方数的路径数. 显然,分解质因数后,若所有的质因子出现的次数都%3==0,则该数是立方数. 于是在模意义下暴力统计即可. 当然,为了不MLE/TLE,我们不能存一个30长度的数组,而要 ...

  4. 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/ ...

  5. HDU 4670 Cube number on a tree ( 树的点分治 )

    题意 : 给你一棵树 . 树的每一个结点都有一个权值 . 问你有多少条路径权值的乘积是一个全然立方数 . 题目中给了你 K 个素数 ( K <= 30 ) , 全部权值都能分解成这k个素数 思路 ...

  6. HDU 4670 Cube number on a tree

    divide and conquer on tree. #include <map> #include <vector> #include <cstdio> #in ...

  7. Square Number & Cube Number

    Square Number: Description In mathematics, a square number is an integer that is the square of an in ...

  8. CodeChef - PRIMEDST Prime Distance On Tree 树分治 + FFT

    Prime Distance On Tree Problem description. You are given a tree. If we select 2 distinct nodes unif ...

  9. 【BZOJ-1468】Tree 树分治

    1468: Tree Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1025  Solved: 534[Submit][Status][Discuss] ...

随机推荐

  1. HttpClient 上传文件

    /// <summary> /// 发送post请求 /// </summary> /// <param name="filePath">文件路 ...

  2. 银联ISO8583报文解析过程

    主密钥: aabbccddeeff11223344556677889900 1.从签到报文中获取工作密钥,包括MACKEY明文,PINKEY明文 签到: 12-03-31 16:38:09----&g ...

  3. 201871010114-李岩松《面向对象程序设计(java)》第十周学习总结

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...

  4. DAGScheduler stage 划分算法

    DAGScheduler stage 划分算法 stage划分算法很重要,对于spark开发人员来说,必须对stage划分算法很清晰,知道自己编写的spark Application被划分成了几个jo ...

  5. 领扣(LeetCode)字母大小写全排列 个人题解

    给定一个字符串S,通过将字符串S中的每个字母转变大小写,我们可以获得一个新的字符串.返回所有可能得到的字符串集合. 示例: 输入: S = "a1b2" 输出: ["a1 ...

  6. shuf

    shi一个排序器,一般用来试用随机输入产生随机乱序的输出,他可以作用于输入文件或者数值范围,也可以对数组进行操作. -i -nN -e 1.掷骰子shuf -i 1-6 -n1 shuf -i 1-6 ...

  7. shell脚本1——变量 $、read、``

    与Shell变量相关的几个命令: 变量只在当前Shell中生效. source 这个命令让脚本影响他们父Shell的环境(. 可以代替source命令) export 这个命令可以让脚本影响其子She ...

  8. objc反汇编分析,手工逆向libsystem_blocks.dylib

    上一篇<block函数块为何物?>介绍了在函数中定义的block函数块的反汇编实现,我在文中再三指出__block变量和block函数块自始还都是stack-based的,还不完全适合在离 ...

  9. 【前端知识体系-JS相关】10分钟搞定JavaScript正则表达式高频考点

    1.正则表达式基础 1.1 创建正则表达式 1.1.1 使用一个正则表达式字面量 const regex = /^[a-zA-Z]+[0-9]*\W?_$/gi; 1.1.2 调用RegExp对象的构 ...

  10. 【Luogu P5490】扫描线

    Luogu P5490 作为一道模板题让我卡了一个月…… 对于线段树+离散化新手而言这实在是太难了…… 有关离散化: 可以查看这一篇文章:https://www.jianshu.com/p/93476 ...