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. Hibernate Query Language查询:

    Hibernate Query Language查询: Criteria查询对查询条件进行了面向对象封装,符合编程人员的思维方式,不过HQL(Hibernate Query Language)查询提供 ...

  2. [转载]php设计模式之单例、多例设计模式

    单例(Singleton)模式和不常见的多例(Multiton)模式控制着应用程序中类的数量.如模式名称,单例只能实例化一次,只有一个对象,多例模式可以多次实例化. 基于Singleton的特性,我们 ...

  3. 帝国CMS“建立目录不成功!请检查目录权限”的解决办法

    初次安装帝国CMS就遇到了一个问题,在提交或者修改信息的时候提示“建立目录不成功!请检查目录权限”,无法生成页面.检查了文件夹的读写权限和用户访问权限,发现都一切正常.那么到底是哪里出错了呢? 其实是 ...

  4. python cython 模块(1)

    python 是一门动态类型的语音,其开发速度比C,C++等静态语言块, 但是速度慢很多, 而cython 通过混合C和python 的语法,可以提高python代码的运行速度 1) 安装cython ...

  5. js 查找指定函数的内容

    function test(){  //hahahhahahhahahha }alert(test.toString());

  6. 什么是集群(Cluster)技术

    什么是集群(Cluster)技术Cluster集群技术可如下定义:一组相互独立的服务器在网络中表现为单一的系统,并以单一系统的模式加以管理.此单一系统为客户工作站提供高可*性的服务.大多数模式下,集群 ...

  7. Chrome各个版本小常识

    摘要: 近期在网上看到chrome有个金丝雀版,第一次看到这个版本,所以就将chrome的各个版本进行了了解,chrome是前端开发最好用的工具,不仅仅是它的调试工具,还有他对HTML5/CSS3的兼 ...

  8. ubuntu普通用户无法使用usdo命令

    1.切换到root用户下,怎么切换就不用说了吧,不会的自己百度去. 2.添加sudo文件的写权限,命令是: chmod u+w /etc/sudoers 3.编辑sudoers文件 vi /etc/s ...

  9. shell基础(六)--字符串和数组

    对文本处理,单独用shell来处理还是比较薄弱.所以shell就引用了awk and sed这两个命令.我们今天不说这个 一 字符串  字符串是shell编程中最常用最有用的数据类型,因为你定义一个变 ...

  10. kafka原理

    今天因为工作接触kafka,先说说kafka是干嘛的. kafka: 说简单点他就是一个基于分布式的消息发布-订阅系统. 然后再理解一些专有名词: Kafka 专用术语 Broker:Kafka 集群 ...