hdu4760

Cube number on a tree

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)

Total Submission(s): 878    Accepted Submission(s): 162

Problem Description
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 Pi(0 ≤ Pi ≤ 1015) 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

题意:

给出一棵树形图,每个顶点都有权值,该权值的所有因子都是给出的k个素数里面的数字,即每个权值都是有给出的素数相乘得到,问存在多少的旅游路线,使所有的权值相乘后是一个立方数(如1,8,27……)因为给出的数是int64范围内的,直接相加比较会超出int64的范围,因此要巧妙的运用给出的素因子的性质,要是总的积是一个立方数,则该立方数的素因子个数一定是3的倍数,因此可以把指数幂转化成三进制的数进行储存,例如2500的因子有2个2,0个3和4个5,对每个数字对3取余之后为产生的三进制表示法是201,对应的十进制是2*3^2+0+1*3^0=19;所以相乘的问题就转换成了三进制数相加的问题了,之后就是树的分治问题。

首先对于一颗子树,求出所有孩子与该根节点(包含根节点)的链的三进制数的和,如果该三进制数是0,则满足条件,然后对于不是0的三进制数,搜索看看是不是存在对立面(对立面为0-该不是0的三进制数),若存在也是一种跨立根节点的满足条件的链

具体过程:对于一个根节点,加入有k个儿子,然后对于每个儿子进行深搜,找到所有经过该儿子和根节点的链,统计满足条件的个数,之后顺便记录该儿子的子树所有节点不包含根节点的链,用num[a]=b记录,即三进制数a的个数有b个,这些数值作为搜下一个儿子子树时的对立面,等该根节点所有儿子的子树搜索完毕之后把num数组清空,重复以上子树遍历过程,最后把每个子树的统计结果相加就是答案:

最后别忘了统计一下某个点自身的权值是不是立方数。

程序:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include"stdio.h"
#include"string.h"
#include"iostream"
#include"map"
#include"string"
#include"queue"
#include"stdlib.h"
#include"math.h"
#define M 50009
#define eps 1e-10
#define inf 99999999
#define mod 1000000000
using namespace std;
struct node
{
int u,v,next;
}edge[M*3];
int t,head[M],use[M],son[M],limit[M],k,MN,ID,cnt,ans;
__int64 prime[33],value[M],cube[33],dis[M];
void init()
{
t=0;
memset(head,-1,sizeof(head));
}
void add(int u,int v)
{
edge[t].u=u;
edge[t].v=v;
edge[t].next=head[u];
head[u]=t++;
}
__int64 Add(__int64 m,__int64 n)
{
int a[33],b[33],i,j;
for(i=0;i<k;i++)
a[i]=b[i]=0;
i=0;
while(m)
{
a[i++]=m%3;
m/=3;
}
j=0;
while(n)
{
b[j++]=n%3;
n/=3;
}
__int64 ss=0;
for(i=0;i<k;i++)
ss+=cube[i]*((a[i]+b[i])%3);
return ss;
}//三进制数相加
__int64 down(__int64 m,__int64 n)
{
int a[33],b[33],i,j;
for(i=0;i<k;i++)
a[i]=b[i]=0;
i=0;
while(m)
{
a[i++]=m%3;
m/=3;
}
j=0;
while(n)
{
b[j++]=n%3;
n/=3;
}
__int64 ss=0;
for(i=0;i<k;i++)
ss+=cube[i]*((3+a[i]-b[i])%3);
return ss;
}//三进制数相减
void dfs_size(int u,int f)
{
son[u]=1;
limit[u]=0;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(f!=v&&!use[v])
{
dfs_size(v,u);
son[u]+=son[v];
limit[u]=max(limit[u],son[v]);
}
}
}
void dfs_root(int root,int u,int f)
{
if(son[root]-son[u]>limit[u])
limit[u]=son[root]-son[u];
if(MN>limit[u])
{
MN=limit[u];
ID=u;
}
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(f!=v&&!use[v])
{
dfs_root(root,v,u);
}
}
}//以上两个递归求树的重心
void dfs_dis(int u,int f,__int64 id)
{
dis[cnt++]=id;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(v!=f&&!use[v])
{
dfs_dis(v,u,Add(id,value[v]));
}
}
}//求子树的权值和
__int64 cal(int u,int f)//对于每个根节点统计满足条件的情况
{
int sum=0;
map<__int64,int>mp;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(v!=f&&!use[v])
{
cnt=0;
dfs_dis(v,u,Add(value[ID],value[v]));
for(int j=0;j<cnt;j++)
{
if(dis[j]==0)
sum++;
__int64 op=down(0,dis[j]);
sum+=mp[op];
}
for(int j=0;j<cnt;j++)
{
mp[down(dis[j],value[ID])]++;
}
}
}
return sum;
}
void dfs_ans(int root,int u,int f)//递归分解子树
{
dfs_size(u,f);
MN=inf;
dfs_root(root,u,f);
ans+=cal(ID,ID);
use[ID]=1;
for(int i=head[ID];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(!use[v])
{
dfs_ans(v,v,v);
}
}
}
void slove(int n)
{
memset(use,0,sizeof(use));
ans=0;
dfs_ans(1,1,1);
for(int i=1;i<=n;i++)
if(value[i]==0)
ans++;
printf("%d\n",ans);
}
int main()
{
int n,i,j;
cube[0]=1;
for(i=1;i<30;i++)
cube[i]=cube[i-1]*3;
while(scanf("%d",&n)!=-1)
{
scanf("%d",&k);
for(i=0;i<k;i++)
scanf("%I64d",&prime[i]);
for(i=1;i<=n;i++)
{
value[i]=0;
__int64 p;
scanf("%I64d",&p);
for(j=0;j<k;j++)
{
int r=0;
while(p%prime[j]==0)
{
p=p/prime[j];
r++;
r%=3;
}
value[i]+=cube[k-j-1]*(r%3);
}
}
init();
for(i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
slove(n);
}
return 0;
}

树链剖分-点的分治(链的点的个数为k的点对数)的更多相关文章

  1. 树链剖分-点的分治(dis[i]+dis[j]==k的点对数量)

    poj2114 Boatherds Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 1195   Accepted: 387 ...

  2. 树链剖分-点的分治(点数为k且距离最长的点对)

    hdu4871 Shortest-path tree Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 130712/130712 K ( ...

  3. bzoj1095: [ZJOI2007]Hide 捉迷藏 线段树维护括号序列 点分治 链分治

    这题真是十分难写啊 不管是点分治还是括号序列都有一堆细节.. 点分治:时空复杂度$O(n\log^2n)$,常数巨大 主要就是3个堆的初始状态 C堆:每个节点一个,为子树中的点到它父亲的距离的堆. B ...

  4. dsu+树链剖分+树分治

    dsu,对于无修改子树信息查询,并且操作支持undo的问题 暴力dfs,对于每个节点,对所有轻儿子dfs下去,然后再消除轻儿子的影响 dfs重儿子,然后dfs暴力恢复轻儿子们的影响,再把当前节点影响算 ...

  5. [2016北京集训试题7]thr-[树形dp+树链剖分+启发式合并]

    Description Solution 神仙操作orz. 首先看数据范围,显然不可能是O(n2)的.(即绝对不是枚举那么简单的),我们考虑dp. 定义f(x,k)为以x为根的子树中与x距离为k的节点 ...

  6. HDU5840 (分块+树链剖分)

    Problem This world need more Zhu 题目大意 给一颗n个点的有点权的树,有m个询问,对于每个询问u,v,k,首先将点u到点v的最短路径上的所有点按顺序编号,u的编号为1, ...

  7. Codeforces Round #329 (Div. 2) D. Happy Tree Party LCA/树链剖分

    D. Happy Tree Party     Bogdan has a birthday today and mom gave him a tree consisting of n vertecie ...

  8. HDU 4718 The LCIS on the Tree(树链剖分)

    Problem Description For a sequence S1, S2, ... , SN, and a pair of integers (i, j), if 1 <= i < ...

  9. BZOJ 3672: [Noi2014]购票( 树链剖分 + 线段树 + 凸包 )

    s弄成前缀和(到根), dp(i) = min(dp(j) + (s(i)-s(j))*p(i)+q(i)). 链的情况大家都会做...就是用栈维护个下凸包, 插入时暴力弹栈, 查询时就在凸包上二分/ ...

随机推荐

  1. Jquery同时绑定多个事件

    //JQ 同时绑定多个事件 $("div.div_grren a img").bind({ mouseover:function(){ $(this).attr('src',bor ...

  2. matlab 等值线函数 contour

    matlab 等值线函数 contour contour是等高线绘制函数我并没怎么用过这个函数,只是参照help将上面的英文翻译一下,如果有错误,请大家提出来.contour(Z)根据矩阵Z画出等高线 ...

  3. EXTJS入门教程及其框架搭建

    EXTJS是一个兼容AJAX的前台WEB UI的框架,在普通的HTML文件的 BODY 元素中无须写任何HTML代码,就能产生相应的表格等元素. 首先是为每一个页面定义一个类,再以EXTJS的规范格式 ...

  4. 《FPGA全程进阶---实战演练》第三章之PCB叠层

    1.双面板 在双层板设计layout时,最好不要不成梳状结构,因为这样构成的电路,回路面积较大,但是只要对较重要的信号加以地保护,布线完成之后将空的地方敷上地铜皮,并在多个过孔将两个地连接起来,可以弥 ...

  5. java---EL与ONGL的区别

    EL表达式: >>单纯在jsp页面中出现,是在四个作用域中取值,page,request,session,application.>>如果在struts环境中,它除了有在上面的 ...

  6. 10 个很有用的高级 Git 命令(转)

    英文原文:10 Useful Advanced Git Commands 迄今,我已经使用Git很长一段时间了,考虑分享一些不管你是团队开发还是个人项目,都受用的高级git命令. 1. 输出最后一次提 ...

  7. Linux新手要了解的十个知识点

    Linux对于有的新手来说,感觉无从下手,或者不知道从哪儿学起?怎么学?针对这些问题,我给大家说说新手学习Linux需要了解的十个知识点. 注意大小写 Linux是大小写敏感的系统,举个例子,Mozi ...

  8. vc 找到一个或多个多重定义的符号

    vc 找到一个或多个多重定义的符号, 这个问题还是不能很好的解决. 最根本的是: 把所有有关定义的部分都放在.cpp文件中,对应的.h文件中只放声明.这样在#include ""的 ...

  9. AI逻辑实现-取舍行为树还是状态机

    AI逻辑实现-选择行为树还是状态机? 关注AI的朋友可能会看过赖勇浩翻译的<有限状态机时代终结的10大理由> ,里面谈到了状态机的诸多弊端.同时在ppt(附上下载地址)中述说了行为树的诸多 ...

  10. HBase 1.3(NOSQL) 发布,性能大幅提升

        Apache HBase 1.3.0版在2017年1月中旬正式发布了,新版本支持分层数据的压缩和多个方面的性能提升,像预写日志(WAL).一个新的RPC机制,等等.HBase 1.3.0一共修 ...