hdu 4670 树的分治-求点对的个数
/*
树的分治
因为树的点权值可达到10^15,注意手动扩栈,还有int64
题意:给你一棵树,给你一些素数,给你每个点一个权值且每个权值均可由这些素数组成。现在定义任意任意两点的价值为他们路径上的权值相乘。求这样的点对的权值为立方数的个数
解:
如果直接求得话会超int64,不可行
由立方数的性质可得,一个数可有素数组成,对于这些素数可以分解为这些素数相乘的形式如,24=(2^3)*(3^1);如果是立方数的话那么他的各进制对3取余都为0.股24可写成01这种三进制形式
对于这些权值的乘法可有三进制想加可得。
接下来就是树的分治了
当然这里可以先求出一条子树上的各个点的权值乘积,然后和根节点和其他字树比较看是否可以互补那么就找到一对
可用map容器实现。因为他重点是比较到根节点和其他子树是否可以互补,进而递归下去,求出每个子树的这样的点对。
*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<map>
#define ll __int64
#define N 51000
#define inf 0x3fffffff
using namespace std;
struct node {
ll u,v,next;
}bian[N*4];
ll yong,head[N];
ll num[N],nn,all[N][51],ff[N][51],minn,m,vis[N],fp[N],ma;
ll prime[51],len;
map<ll,ll>q;
void init() {
yong=0;
memset(head,-1,sizeof(head));
}
void addedge(ll u,ll v) {
bian[yong].u=u;
bian[yong].v=v;
bian[yong].next=head[u];
head[u]=yong++;
}
void dfs1(ll u,ll fa) {//找到每次根子树的的节点数目
ll i;
nn++;
for(i=head[u];i!=-1;i=bian[i].next) {
ll v=bian[i].v;
if(v!=fa&&!vis[v])
dfs1(v,u);
}
return ;
}
ll Max(ll v,ll vv) {
return v>vv?v:vv;
}
void dfs2(ll u,ll fa) {//找重心
num[u]=1;
ll i,tit=0;
for(i=head[u];i!=-1;i=bian[i].next) {
ll v=bian[i].v;
if(v!=fa&&!vis[v]) {
dfs2(v,u);
num[u]+=num[v];
tit=Max(tit,num[v]);
}
}
tit=Max(tit,nn-num[u]);
if(tit<minn) {
minn=tit;
ma=u;
}
return ;
}
void dfs4(ll u,ll fa) {
ll i;
//prllf("dfs4=%d",u);
if(fa!=-1) {
ll e=fp[fa];
for(i=1;i<=m;i++)
all[len][i]=(all[e][i]+ff[u][i])%3;
}
else {
for(i=1;i<=m;i++)
all[len][i]=ff[u][i];
}
fp[u]=len++;
for(i=head[u];i!=-1;i=bian[i].next) {
ll v=bian[i].v;
if(v!=fa&&!vis[v])
dfs4(v,u);
}
return ;
}
ll dfs3(ll u) {//求以当前子树为根的符合条件的对数
ll i,ans=0,j,k;
ll s1,s2;
s1=0;
q.clear();
for(i=1;i<=m;i++)
s1=s1*3+ff[u][i];
if(s1==0)ans++;
//prllf("ma=%d,s1=%d\n",ma,s1);
q[s1]=1;
for(i=head[u];i!=-1;i=bian[i].next) {
ll v=bian[i].v;
if(vis[v])continue;
len=0;
dfs4(v,-1);
// prllf("len=%d\n",len);
for(j=0;j<len;j++) {//进行互补
s1=0;
for(k=1;k<=m;k++)
s1=s1*3+(3-all[j][k])%3;
// prllf("zzs1=%d\n",s1);
ans+=q[s1];
}
for(j=0;j<len;j++) {
s2=0;
for(k=1;k<=m;k++)
s2=s2*3+(all[j][k]+ff[u][k])%3;//到根结点的权值,为下次互补做准备,同时避免重复
q[s2]++;
}
// prllf("aad%d\n",ans);
}
return ans;
}
ll dfs(ll u) {
minn=inf;
nn=0;
dfs1(u,-1);
dfs2(u,-1);//求重心
vis[ma]=1;
ll ans=dfs3(ma);
// prllf("ma=%d\n",ma);
//prllf("ans=%d\n",ans);
ll i;
for(i=head[ma];i!=-1;i=bian[i].next) {
ll v=bian[i].v;
if(!vis[v])
ans+=dfs(v);
}
return ans;
}
int main() {
ll n,i,j,k,kk;
while(scanf("%I64d",&n)!=EOF) {
init();
scanf("%I64d",&m);
for(i=1;i<=m;i++)
scanf("%I64d",&prime[i]);
for(i=1;i<=n;i++) {
scanf("%I64d",&k);
for(j=1;j<=m;j++) {
kk=0;
while(k%prime[j]==0) {
k/=prime[j];
kk++;
kk%=3;
}
ff[i][j]=kk;
}
}
for(i=1;i<n;i++) {
scanf("%I64d%I64d",&j,&k);
addedge(j,k);
addedge(k,j);
}
memset(vis,0,sizeof(vis));
printf("%I64d\n",dfs(1));
}
return 0;}
hdu 4670 树的分治-求点对的个数的更多相关文章
- hdu 4638 树状数组 区间内连续区间的个数(尽可能长)
Group Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Subm ...
- hdu 4871 树的分治+最短路记录路径
/* 题意:给你一些节点和一些边,求最短路径树上是k个节点的最长的路径数. 解:1.求出最短路径树--spfa加记录 2.树上进行操作--树的分治,分别处理子树进行补集等运算 */ #include& ...
- hdu 4670 树的点分治
思路:首先当然是要用树的点分治了.根节点为root,那么经过root的合法路径数求出来这题就解决了.因为我们可以用分治枚举根,最后将所有根的路径数加起来就是结果.当然这里的根不是整棵树的根,是子树根. ...
- HDU 1394 树状数组求逆序对
Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java ...
- hdu 1007 Quoit Design 分治求最近点对
Quoit Design Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Tot ...
- Hdu 2586 树链剖分求LCA
Code: #include<cstdio> #include<cstring> #include<vector> #include<algorithm> ...
- HDU X问题 中国剩余定理--求满足条件的个数
X问题 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...
- Coconuts HDU - 5925 (二维离散化求连通块的个数以及大小)
题目链接: D - Coconuts HDU - 5925 题目大意:首先是T组测试样例,然后给你n*m的矩阵,原先矩阵里面都是白色的点,然后再输入k个黑色的点.这k个黑色的点可能会使得原先白色的点 ...
- hdu 1257 最少拦截系统 求连续递减子序列个数 (理解二分)
最少拦截系统 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Subm ...
随机推荐
- bzoj 1690: [Usaco2007 Dec]奶牛的旅行【01分数规划+spfa】
把add传参里的double写成int我也是石乐志-- 首先这个东西长得就很01分数规划 然后我不会证为什么没有8字环,我们假装他没有 那么设len为环长 \[ ans \leq \frac{\sum ...
- 学习http协议的三次握手和四次挥手 ~~笔记
http协议是基于tcp协议的 所以应该说是tcp协议的三次握手和四次挥手 SYN:请求建立连接,并在其序列号的字段进行序列号的初始值设定.建立连接,设置为1 FIN:用来释放一个连接.FIN=1表 ...
- python2行代码调用程序
import win32api win32api.ShellExecute(0, 'open', r'C:\Users\TOPFEEL\AppData\Local\Postman\app-5.5.0\ ...
- 373 Find K Pairs with Smallest Sums 查找和最小的K对数字
给定两个以升序排列的整形数组 nums1 和 nums2, 以及一个整数 k.定义一对值 (u,v),其中第一个元素来自 nums1,第二个元素来自 nums2.找到和最小的 k 对数字 (u1,v1 ...
- Spark性能优化指南-高级篇(spark shuffle)
Spark性能优化指南-高级篇(spark shuffle) 非常好的讲解
- Modbus消息帧
两种传输模式中(ASCII和RTU),传输设备以将Modbus消息转为有起点和终点的帧,这就允许接收的设备在消息起始处开始工作,读地址分配信息,判断哪一个设备被选中(广播方式则传给所以设备),判知何时 ...
- Laravel5.1学习笔记22 Eloquent 调整修改
Eloquent: Mutators Introduction Accessors & Mutators Date Mutators Attribute Casting Introductio ...
- 读《实战 GUI 产品的自动化测试》之:第二步,构建利于维护的自动化测试系统
转载自:http://www.ibm.com/developerworks/cn/rational/r-cn-guiautotesting2/ 基石——IBM 框架简介 Rational Functi ...
- JsTree中节点添加CheckBox 以及 单选的实现
stree中添加checkbox,需要在初始化时设置plugins属性: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 $('#DpTree').data('jstree', fa ...
- CAD插入图片
在CAD设计绘图时,需要插入外部图片,可以设置图片的缩放比例.旋转角度.图片显示文件名等属性. 主要用到函数说明: _DMxDrawX::DrawImageMark 绘图制一个图象标记对象.详细说明如 ...