HDU4670 Cube number on a tree 树分治
人生的第一道树分治,要是早点学我南京赛就不用那么挫了,树分治的思路其实很简单,就是对子树找到一个重心(Centroid),实现重心分解,然后递归的解决分开后的树的子问题,关键是合并,当要合并跨过重心的两棵子树的时候,需要有一个接近O(n)的方法,因为f(n)=kf(n/k)+O(n)解出来才是O(nlogn).在这个题目里其实就是将第一棵子树的集合里的每个元素,判下有没符合条件的,有就加上,然后将子树集合压进大集合,然后继续搞第二棵乃至第n棵.我的过程用了map,合并是nlogn的所以代码速度颇慢,大概6s,题目时限10s,可以改成hash应该会快许多,毕竟用map实在太慢,用vector也可以,具体可以参见挑战程序设计竞赛代码.下面的代码查找重心用了挑战的代码.
#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
#include<map>
#include<vector>
#define maxv 50000
#define ll long long
using namespace std; int n,k;
vector<int> G[maxv+50];
ll val[maxv+50];
ll prime[maxv+50];
ll convert_three(ll v)
{
ll bas=1;ll res=0;
for(int i=0;i<k;++i){
int num=0;
while(v%prime[i]==0){
v/=prime[i];
num++;
}
num%=3;res+=num*bas;
bas*=3;
}
return res;
} ll xor(ll x,ll y)
{
ll res=0;ll bas=1;
for(int i=0;i<k;++i){
res+=((x%3)+(y%3))%3*bas;
x/=3;y/=3;
bas*=3;
}
return res;
} ll inv(ll x)
{
ll res=0;ll bas=1;
for(int i=0;i<k;++i){
res+=((3-(x%3))%3)*bas;
x/=3;
bas*=3;
}
return res;
} void print(ll x){
while(x){
cout<<x%3;
x/=3;
}
cout<<endl;
} bool centroid[maxv+50];
int ssize[maxv+50];
int ans; map<ll,int> sta;
map<ll,int>::iterator it;
int compute_ssize(int v,int p)
{
int c=1;
for(int i=0;i<G[v].size();++i){
int w=G[v][i];
if(w==p||centroid[w]) continue;
c+=compute_ssize(G[v][i],v);
}
ssize[v]=c;
return c;
} pair<int,int> search_centroid(int v,int p,int t)
{
pair<int,int> res=make_pair(INT_MAX,-1);
int s=1,m=0;
for(int i=0;i<G[v].size();++i){
int w=G[v][i];
if(w==p||centroid[w]) continue;
res=min(res,search_centroid(w,v,t));
m=max(m,ssize[w]);
s+=ssize[w];
}
m=max(m,t-s);
res=min(res,make_pair(m,v));
return res;
} void enumerate_mul(int v,int p,ll d,map<ll,int> &ds)
{
if(ds.count(d)) ds[d]++;
else ds[d]=1;
for(int i=0;i<G[v].size();++i){
int w=G[v][i];
if(w==p||centroid[w]) continue;
enumerate_mul(w,v,xor(d,val[w]),ds);
}
} void solve(int v)
{
compute_ssize(v,-1);
int s=search_centroid(v,-1,ssize[v]).second;
centroid[s]=true;
for(int i=0;i<G[s].size();++i){
if(centroid[G[s][i]]) continue;
solve(G[s][i]);
}
sta.clear();
sta[val[s]]=1;map<ll,int> tds;
for(int i=0;i<G[s].size();++i){
if(centroid[G[s][i]]) continue;
tds.clear();
enumerate_mul(G[s][i],s,val[G[s][i]],tds);
it=tds.begin();
while(it!=tds.end()){
ll rev=inv((*it).first);
if(sta.count(rev)){
ans+=sta[rev]*(*it).second;
}
++it;
}
it=tds.begin();
while(it!=tds.end()){
ll vv=xor((*it).first,val[s]);
if(sta.count(vv)){
sta[vv]+=(*it).second;
}
else{
sta[vv]=(*it).second;
}
++it;
}
}
centroid[s]=false;
} int main()
{
while(cin>>n>>k){
ans=0;
for(int i=0;i<k;++i){
scanf("%I64d",&prime[i]);
}
G[0].clear();
for(int i=1;i<=n;++i){
scanf("%I64d",&val[i]);
val[i]=convert_three(val[i]);
if(val[i]==0) ans++;
//print(val[i]);
G[i].clear();
}
int u,v;
for(int i=0;i<n-1;++i){
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
memset(centroid,0,sizeof(centroid));
solve(1);
printf("%d\n",ans);
}
return 0;
}
HDU4670 Cube number on a tree 树分治的更多相关文章
- HDU4670 cube number on a tree(点分治+三进制加法)
The country Tom living in is famous for traveling. Every year, many tourists from all over the world ...
- [hdu4670 Cube number on a tree]点分治
题意:给一个N个带权节点的树,权值以给定的K个素数为因子,求路径上节点乘积为立方数的路径条数 思路:立方数的性质是每个因子的个数为3的倍数,那么每个因子只需要保存0-2三个状态即可,然后路径就可以转化 ...
- HDU 4670 Cube number on a tree ( 树的点分治 )
题意 : 给你一棵树 . 树的每一个结点都有一个权值 . 问你有多少条路径权值的乘积是一个全然立方数 . 题目中给了你 K 个素数 ( K <= 30 ) , 全部权值都能分解成这k个素数 思路 ...
- 【点分治】【map】【哈希表】hdu4670 Cube number on a tree
求树上点权积为立方数的路径数. 显然,分解质因数后,若所有的质因子出现的次数都%3==0,则该数是立方数. 于是在模意义下暴力统计即可. 当然,为了不MLE/TLE,我们不能存一个30长度的数组,而要 ...
- hdu 4670 Cube number on a tree(点分治)
Cube number on a tree Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/ ...
- 【BZOJ-1468】Tree 树分治
1468: Tree Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1025 Solved: 534[Submit][Status][Discuss] ...
- HDU 4812 D Tree 树分治+逆元处理
D Tree Problem Description There is a skyscraping tree standing on the playground of Nanjing Unive ...
- POJ 1741 Tree 树分治
Tree Description Give a tree with n vertices,each edge has a length(positive integer less than 1 ...
- POJ 1741.Tree 树分治 树形dp 树上点对
Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 24258 Accepted: 8062 Description ...
随机推荐
- Jquery 学习三
一.each语句 1.each语句的功能 在jQuery中,通过$函数获取的都是jQuery对象.通过测试可知,jQuery对象是一个类数组的特殊对象,其是DOM对象的集合.而each语句就是专门用于 ...
- 《openstack 和hadoop的区别是什么?》
openstack 和hadoop的区别是什么? (一) openstack仿照的Amazon的云,hadoop仿照的是Google的云 openstack注重的是虚拟化/虚拟机及其配套的服务,had ...
- CSS1-CSS3 <color>颜色知识知多少?
非本人原创,原文转载自http://www.zhangxinxu.com/wordpress/2015/07/know-css1-css3-color/ by zhangxinxu from http ...
- liunx下vi命令详解
vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器,这里只是简单地介绍一下它的用法和一小部分指令.由于对Unix及Linux系统的任何版本,vi编辑器是完全相 ...
- python学习第七天
一. subprocess 模块 1. subprocess的介绍:用来替代几个老的模块或是函数,如:os.systam,os.popen,os.spawn*,os.popen2*,co ...
- 1. opencv的初体验
http://guoming.me/opencv-config 这篇文章有讲解opencv的安装与配置 一些常用库 opencv_core249d.lib opencv_imgproc249d.li ...
- zendframework 事件管理(二)
首先需要明确的几个问题: Q1.什么是事件? A:事件就是一个有名字的行为.当这个行为发生的时候,称这个事件被触发. Q2.监听器又是什么? A:监听器决定了事件的逻辑表达,由事件触发.监听器和事件往 ...
- apache2: bad user name ${APACHE_RUN_USER} 解决
开工后,发现有个虚拟机的apache没起来,调用apache2 -k start 后,提示如下内容: apache2: bad user name ${APACHE_RUN_USER} apache ...
- myeclipse ctrl+shift+F失效
因为在使用搜狗输入法,切换到英文状态,输入ctrl+shift+F,格式化完之后,然后再换回来
- SQL Server 2008之数据库大型应用解决方案总结
着互联网应用的广泛普及,海量数据的存储和访问成为了系统设计的瓶颈问题.对于一个大型的互联网应用,每天百万级甚至上亿的PV无疑对数据库造成了相当高的负载.对于系统的稳定性和扩展性造成了极大的问题. 一. ...