树链剖分-点的分治(链的点的个数为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)). 链的情况大家都会做...就是用栈维护个下凸包, 插入时暴力弹栈, 查询时就在凸包上二分/ ...
随机推荐
- [随想感悟] 面试时,问哪些问题能试出一个 Android 应用开发者真正的水平?【转自知乎】
这几年面过的各种Android开发也有三位数了,failed的不敢说,pass的基本都没有看走眼,来得晚了也想说说我的体会. 一般面试时间短则30分钟,多则1个小时,这么点时间要全面考察一个人难度很大 ...
- English Sentenses【no use】
1.Sorry if I might sound arrogant or offensive. 2.Any further question? 3.How dare you! 4.Try it if ...
- jenkins配置过程遇到的问题
jenkins 搭建完成后,可以浏览器访问: http://localhost:8081/jenkins, 新建任务过程中遇到以下问题: 1. 源码管理不现实git, 只显示无 解决: 插件管理 - ...
- Spring的p标签
看Spring in action的时候看过p标签,可惜这东西不用就忘. p标签是为了简化setter的注入而引入的. 用法: p:属性 = "{值}" p:属性-ref = &q ...
- 10个最佳的触控手式的JavaScript框架(转)
由于各种原因移动开发是一项艰难的工作,比如它是非常耗时的.充满压力的任务.最重要的是,作为一个开发人员,你必须保持更新所有最新 的技术和技巧——你必须知道所有最新的趋势,问题和解决方案等.例如跨浏览器 ...
- find_circ 识别circRNA 的原理
find_circ 通过识别junction reads 来预测circRNA 和参考基因组比对完之后,首先剔除和基因组完全比对的reads,保留没比对上的reads, 这部分reads 直接比是比对 ...
- 做游戏长知识------基于行为树与状态机的游戏AI(一)
孙广东 2014.6.30 AI. 我们的第一印象可能是机器人,如今主要说在游戏中的应用. 现代的计算机游戏中已经大量融入了AI元素,平时我们进行游戏时产生的交互都是由AI来完毕的.比方在RPG游戏中 ...
- iotop详解
有时我们希望知道到底哪个进程产生了IO,这个时候就需要iotop这个工具了.它的输出和top命令类似,简单直观.官网:http://guichaz.free.fr/iotop/需要Python 2.5 ...
- Unity带参数的协程
两种方法都可以传递参数,代码如下: using UnityEngine; using System.Collections; public class Test : MonoBehaviour { v ...
- android webView不简单
手机屏幕大小非常伤程序猿 励志成为一名Javaproject师的我.真的被它伤到了,不仅由于webView的强大.并且这个内容适合各样屏幕大小问题. 想当年苹果project师嘲笑安卓project师 ...