树链剖分-点的分治(链的点的个数为k的点对数)
Cube number on a tree
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.
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.
5
3 2 3 5
2500 200 9 270000 27
4 2
3 5
2 5
4 1
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的点对数)的更多相关文章
- 树链剖分-点的分治(dis[i]+dis[j]==k的点对数量)
poj2114 Boatherds Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 1195 Accepted: 387 ...
- 树链剖分-点的分治(点数为k且距离最长的点对)
hdu4871 Shortest-path tree Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 130712/130712 K ( ...
- bzoj1095: [ZJOI2007]Hide 捉迷藏 线段树维护括号序列 点分治 链分治
这题真是十分难写啊 不管是点分治还是括号序列都有一堆细节.. 点分治:时空复杂度$O(n\log^2n)$,常数巨大 主要就是3个堆的初始状态 C堆:每个节点一个,为子树中的点到它父亲的距离的堆. B ...
- dsu+树链剖分+树分治
dsu,对于无修改子树信息查询,并且操作支持undo的问题 暴力dfs,对于每个节点,对所有轻儿子dfs下去,然后再消除轻儿子的影响 dfs重儿子,然后dfs暴力恢复轻儿子们的影响,再把当前节点影响算 ...
- [2016北京集训试题7]thr-[树形dp+树链剖分+启发式合并]
Description Solution 神仙操作orz. 首先看数据范围,显然不可能是O(n2)的.(即绝对不是枚举那么简单的),我们考虑dp. 定义f(x,k)为以x为根的子树中与x距离为k的节点 ...
- HDU5840 (分块+树链剖分)
Problem This world need more Zhu 题目大意 给一颗n个点的有点权的树,有m个询问,对于每个询问u,v,k,首先将点u到点v的最短路径上的所有点按顺序编号,u的编号为1, ...
- 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 ...
- 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 < ...
- BZOJ 3672: [Noi2014]购票( 树链剖分 + 线段树 + 凸包 )
s弄成前缀和(到根), dp(i) = min(dp(j) + (s(i)-s(j))*p(i)+q(i)). 链的情况大家都会做...就是用栈维护个下凸包, 插入时暴力弹栈, 查询时就在凸包上二分/ ...
随机推荐
- 外部引用CSS中 link与@import的区别
差别1:link属于XHTML标签,而@import完全是CSS提供的一种方式. link标签除了可以加载CSS外,还可以做很多其它的事情,比如定义RSS,定义rel连接属性等,@import就只能加 ...
- WCF(一)
摘自:http://www.cnblogs.com/yank/p/3653160.html WCF入门教程(一)简介 1.WCF是什么? WCF( Windows Communication Foun ...
- android 虚拟键盘控制
软键盘显示的原理 软键盘的本质是什么?软键盘其实是一个Dialog! InputMethodService为我们的输入法创建了一个Dialog,并且将该Dialog的Window的某些参数(如Grav ...
- e1086. if/else语句
The if statement encloses some code which is executed only if a condition is true. The general synta ...
- 电脑的CPU可直接解读的数据机器码
机器语言(machine language)是一种指令集的体系.这种指令集,称机器码(machine code),是电脑的CPU可直接解读的数据. 机器码有时也被称为原生码(Native Code), ...
- bedtools 的安装与使用
1) 安装 bedtools 提供了3种安装方式 从google code 下载源代码进行安装 利用系统中的包管理工具进行安装, 比如cnetos 下的yum, ubuntu下的apt-get, ma ...
- 获取作为 URL 部署清单的位置。
ActivationContext ac = AppDomain.CurrentDomain.ActivationContext; ApplicationIdentity ai = ac.Identi ...
- MVC中导航菜单,选中项的高亮问题。。
先上图: 这个菜单是放在母板页的.比如当前选中的是异常业务监控.如果页面刷新了.就会变成第一张图..选择其他的选项也会,因为页面会刷新嘛.. 怎么处理这个问题了? 答案是记录当 ...
- Discuz论坛post登录C#源码
总结: loginhash formhash 表单参数 seccode 参数最重要 全局 的 获取验证码 判断验证码 到最后提交登录 它都有存在 ,seccode==idhash COOKIE自动维 ...
- 用MathType怎么编辑带圈数字序号
在用MathType编辑公式时,涉及到的数学公式与符号这些都能编辑出来,只要你能够细心一点找到它们相应的模板,不管是在word公式编辑器MathType工具栏模板中,还是在插入符号之后的面板中都可以. ...