HDU 4670 Cube number on a tree ( 树的点分治 )
题意 : 给你一棵树 。 树的每一个结点都有一个权值 。 问你有多少条路径权值的乘积是一个全然立方数 。
题目中给了你 K 个素数 ( K <= 30 ) , 全部权值都能分解成这k个素数
思路 : 一个全然立方数的素因子个数都是三的倍数 , 所以我们仅仅要求各个素数的个数即可了 , 而且我们仅仅关心个数对三的余数
所以我们能够用一个 长整形来表示每一个结点到根的各个素因子的个数( 三进制压缩 ) 。
只是由于用位运算会快一点 , 所以我用了四进制。即每两位表示一个素因子的个数 。
中间合并的时候计算刚好相加之后变成0的数,然后用map统计就能够了
注意 : 题目中 pi 的值 , 0 是取不到的( 纠结了好久该怎么处理 = = )
#include <stdio.h>
#include <string.h>
#include <map>
#include <algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std; #define MAXN 50005
#define INF 0x3f3f3f3f
__int64 prime[35] ;
int n , k ; struct Tree{
struct Edge{
int to , nex ;
Edge(){}
Edge( int _to , int _nex ) {
to = _to ;
nex = _nex ;
}
}edge[MAXN*2] ; int head[MAXN] ;
int Index ; void init(){
memset( head , -1 , sizeof(head) ) ;
Index = 0 ;
} void add( int from , int to ) {
edge[Index] = Edge( to , head[from] ) ;
head[from] = Index ++ ;
}
} tree ; inline int get( __int64 val , int pos ) {
return ( val >> ( pos << 1 ) ) & 3 ;
} inline void set( __int64 & val , int pos , int k ) {
val |= ( (__int64)k << ( pos << 1 ) ) ;
} __int64 add( __int64 a , __int64 b ) {
__int64 ans = 0 ;
for( int i = 0 ; i < k ; i ++ ) {
int aa = get( a , i ) ;
int bb = get( b , i ) ;
aa += bb ;
aa %= 3 ; ;
set( ans , i , aa ) ;
}
return ans ;
} __int64 fan( __int64 a ) {
__int64 ans = 0 ;
for( int i = 0 ; i < k ; i ++ ) {
int tmp = get( a , i ) ;
tmp = 3 - tmp ;
set( ans , i , tmp % 3 ) ;
}
return ans ;
} bool vis[MAXN] ;
__int64 val[MAXN] ;
__int64 ans ; // 第i结点为根的子树的最大个数
int dp[MAXN] ;
// 第i结点为根的子树的大小
int sum[MAXN] ; int Sum ;
int Min , Minid ; void dfs1( int u , int f ) {
sum[u] = 1 ;
dp[u] = 0 ;
for( int i = tree.head[u] ; ~i ; i = tree.edge[i].nex ) {
int ch = tree.edge[i].to ;
if( ch == f || vis[ch] ) continue ;
dfs1( ch , u ) ;
sum[u] += sum[ch] ;
dp[u] = max( dp[u] , sum[ch] ) ;
}
} void dfs2( int u , int f ) {
int M = max( dp[u] , Sum - sum[u] ) ;
if( M < Min ) {
Min = M ;
Minid = u ;
}
for( int i = tree.head[u] ; ~i ; i = tree.edge[i].nex ) {
int ch = tree.edge[i].to ;
if( ch == f || vis[ch] ) continue ; dfs2( ch , u ) ;
}
} // 返回树的重心
int getRoot( int u ) {
// 第一遍dfs求出全部点的子树大小。和以孩子为跟的子树个数的最大值
dfs1( u , 0 ) ;
Sum = sum[u] ;
Min = 0x3f3f3f3f ;
Minid = -1 ;
// 第二次dfs求重心
/* 事实上假设整棵树求重心的话,我们一边dfs即可。由于这个是部分树,我们要dfs来确定哪些结点在当前树中 */
dfs2( u , 0 ) ;
return Minid ;
} int tot ;
__int64 Val[MAXN] ; void getVal( int u , int fa , __int64 vv ) {
Val[tot++] = add( vv , val[u] ) ;
for( int i = tree.head[u] ; ~i ; i = tree.edge[i].nex ) {
int to = tree.edge[i].to ;
if( vis[to] == true )
continue ;
if( to == fa ) continue ;
getVal( to , u , add( vv , val[u] ) ) ;
}
} map<__int64,int> mp ; __int64 cal( int root , __int64 val , __int64 root_val ) {
tot = 0 ;
getVal( root , 0 , val ) ;
//sort( Val , Val + tot ) ;
mp.clear() ;
__int64 ans = 0 ;
for( int i = 0 ; i < tot ; i ++ ) {
ans += mp[ add( root_val , fan(Val[i]) ) ] ;
mp[Val[i]] ++ ;
}
return ans ;
} void solve( int u ) {
// 得到当前子树的重心
int root = getRoot( u ) ;
// 计算以root为根的结果
ans += cal( root , 0 , val[root] ) ;
if( val[root] == 0 ) ans ++ ;
vis[root] = true ;
for( int i = tree.head[root] ; ~i ; i = tree.edge[i].nex ) {
int ch = tree.edge[i].to ;
if( vis[ch] ) continue ;
ans -= cal( ch , val[root] , val[root] ) ;
solve( ch ) ;
}
} int main(){
while( scanf( "%d" , &n ) != EOF ) {
scanf( "%d" , &k ) ;
for( int i = 0 ; i < k ; i ++ ) {
scanf( "%d" , &prime[i] ) ;
}
tree.init() ;
memset( vis , false , sizeof(vis) );
memset( val , 0 , sizeof(val) ) ;
for( int i = 1 ; i <= n ; i ++ ) {
__int64 tmp ;
scanf( "%I64d" , &tmp ) ;
for( int j = 0 ; j < k ; j ++ ) {
int cnt = 0 ;
while( tmp % prime[j] == 0 ) {
cnt ++ ;
tmp /= prime[j] ;
}
cnt %= 3 ;
set( val[i] , j , cnt ) ;
}
}
for( int i = 0 ; i < n - 1 ; i ++ ) {
int u , v ;
scanf( "%d%d" , &u , &v ) ;
tree.add( u , v ) ;
tree.add( v , u ) ;
}
ans = 0 ;
solve( 1 ) ;
printf( "%I64d\n" , ans ) ;
}
return 0 ;
}
HDU 4670 Cube number on a tree ( 树的点分治 )的更多相关文章
- 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/ ...
- HDU 4670 Cube number on a tree
divide and conquer on tree. #include <map> #include <vector> #include <cstdio> #in ...
- HDU4670 Cube number on a tree 树分治
人生的第一道树分治,要是早点学我南京赛就不用那么挫了,树分治的思路其实很简单,就是对子树找到一个重心(Centroid),实现重心分解,然后递归的解决分开后的树的子问题,关键是合并,当要合并跨过重心的 ...
- HDU4670 cube number on a tree(点分治+三进制加法)
The country Tom living in is famous for traveling. Every year, many tourists from all over the world ...
- hdu 4812 D Tree(树的点分治)
D Tree Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 102400/102400 K (Java/Others) Total ...
- 【poj1741】Tree 树的点分治
题目描述 Give a tree with n vertices,each edge has a length(positive integer less than 1001). Define dis ...
- POJ1741——Tree(树的点分治)
1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2013-11-17 1 ...
- HDU 5614 Baby Ming and Matrix tree 树链剖分
题意: 给出一棵树,每个顶点上有个\(2 \times 2\)的矩阵,矩阵有两种操作: 顺时针旋转90°,花费是2 将一种矩阵替换为另一种矩阵,花费是10 树上有一种操作,将一条路经上的所有矩阵都变为 ...
- [hdu4670 Cube number on a tree]点分治
题意:给一个N个带权节点的树,权值以给定的K个素数为因子,求路径上节点乘积为立方数的路径条数 思路:立方数的性质是每个因子的个数为3的倍数,那么每个因子只需要保存0-2三个状态即可,然后路径就可以转化 ...
随机推荐
- 监听器(web基础学习笔记二十二)
一.监听器 监听器是一个专门用于对其他对象身上发生的事件或状态改变进行监听和相应处理的对象,当被监视的对象发生情况时,立即采取相应的行动.监听器其实就是一个实现特定接口的普通java程序,这个程序专门 ...
- PACS系统简易
PACS系统 http://baike.baidu.com/link?url=prHBMbyu5W98ET1UGQ0PXXxLebxAeljckFH0pfO_2aODe1UgsrWgRd4Unbopt ...
- js replace 如何替换字符串中的最后一个匹配项
1.正则表达时,贪婪模式,.*会一直匹配到最后一个 // 验证 let str = "123[空]345[空]789[空]0"; let res = str.replace(/(. ...
- yml 配置文件注入
配置文件 JavaBean 自动提示 测试
- 如何在Eclipse中查看JDK以及Java框架的源码
方法一:快速简单 第一步: 打开你的Eclipse,然后随便找一个Java文件,随便找一个Java类库,比如String什么的,然后按住Ctrl,再点击它,你会发现跳到如下界面: 你会发现报错了:So ...
- 分离Command
要点: 1.请求类必须继承CommandBase 2.请求类类名为请求对象中的Key值,大小写可以不区分 3.类必须用public修饰,否则无法识别该请求,提示为无效请求 4.不能再调用NewRequ ...
- 24、java操作xml方法
XML解析方式 1. SAX解析方式 SAX(simple API for XML)是一种XML解析的替代方法.相比于DOM,SAX是一种速度更快,更有效的方法.它逐行扫描文档,一边扫描一边解析.而且 ...
- HDUOJ ------1398
http://acm.hdu.edu.cn/showproblem.php?pid=1398 Square Coins Time Limit: 2000/1000 MS (Java/Others) ...
- JavaScript 设计模式之建造者模式
一.建造者模式概念解读 1.建造者模式概念文字解读 建造者模式可以将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示.也就是说如果我们用了建造者模式,那么用户就需要指定需要建造的类 ...
- 有效Log4j按指定级别定向输出日志到指定的输出文件地址配置Threshold,log4j中如何屏蔽父logger输出源rootlogger的additivity配置,log4j向多个文件记录日志
log4j向多个文件记录日志 关键配置,指定想要的日志级别信息输出到指定的日志文件中: log4j.appender.errorLogger.Threshold=ERROR #扩展,可指定只在子类自己 ...