【HDU】4812 D Tree 点分治

2024-09-05 14:48
文章标签 tree 分治 hdu 4812

本文主要是介绍【HDU】4812 D Tree 点分治,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

传送门:【HDU】4812 D Tree


题目分析:点分治搞之。乘积等于K的路径。


首先我们定义一个path[ i ]用以记录从根结点x在子树x内的第 i 条路径的值(乘积)。然后每次我们搞完当前重心rt的一棵子树以后,我们用判断K*逆元[ path[ i ] * val[ rt ] %MOD ] % MOD 是否存在来确定乘积为K的路径是否存在,然后再用这个path[ i ]去更新best[ path[ i ] ](best[ i ]为取值为 i 的路径的端点最小标号 )。

求逆元可以用p^(mod - 2 ) % mod来,毕竟互素随便搞?


代码如下:


#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;typedef long long LL ;#pragma comment(linker,"/STACK:102400000,102400000")#define travel( e , H , u ) for ( Edge* e = H[u] ; e ; e = e -> next )
#define rep( i , a , b ) for ( int i = ( a ) ; i <  ( b ) ; ++ i )
#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )
#define FOR( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )
#define clr( a , x ) memset ( a , x , sizeof a )
#define cpy( a , x ) memcpy ( a , x , sizeof a )const int MAXN = 100005 ;
const int MAXE = 200005 ;
const int MOD = 1000003 ;
const int INF = 0x3f3f3f3f ;struct Edge {int v ;Edge* next ;
} E[MAXE] , *H[MAXN] , *edge ;struct Node {int c , idx ;Node () {}Node ( int idx , int c ) : idx ( idx ) , c ( c ) {}
} path[MAXN] ;int flag[MOD] ;
int ni[MOD] ;
int best[MOD] ;
bool vis[MAXN] ;
int val[MAXN] ;
int siz[MAXN] ;
int num[MAXN] ;
int node_num ;
int ans[2] ;
int n , K ;
int root ;
int cnt ;//path
int dep ;//flagvoid clear () {dep = 0 ;edge = E ;num[0] = n ;clr ( H , 0 ) ;clr ( vis , 0 ) ;clr ( flag , 0 ) ;ans[0] = ans[1] = INF ;
}void addedge ( int u , int v ) {edge -> v = v ;edge -> next = H[u] ;H[u] = edge ++ ;
}int pow ( int a , int b ) {LL res = 1 , tmp = a ;while ( b ) {if ( b & 1 ) res = res * tmp % MOD ;tmp = tmp * tmp % MOD ;b >>= 1 ;}return res ;
}void get_siz ( int u , int fa = 0 ) {siz[u] = 1 ;travel ( e , H , u ) {int v = e -> v ;if ( !vis[v] && v != fa ) {get_siz ( v , u ) ;siz[u] += siz[v] ;}}
}void get_root ( int u , int fa = 0 ) {num[u] = 0 ;travel ( e , H , u ) {int v = e -> v ;if ( !vis[v] && v != fa ) {get_root ( v , u ) ;num[u] = max ( num[u] , siz[v] ) ;}}num[u] = max ( num[u] , node_num - siz[u] ) ;if ( num[u] < num[root] ) root = u ;
}void get_path ( int u , int c , int fa = 0 ) {path[cnt ++] = Node ( u , c ) ;travel ( e , H , u ) {int v = e -> v ;if ( !vis[v] && v != fa ) {get_path ( v , ( LL ) c * val[v] % MOD , u ) ;}}
}void update_ans ( int u , int v ) {if ( u > v ) swap ( u , v ) ;if ( u < ans[0] || u == ans[0] && v < ans[1] ) ans[0] = u , ans[1] = v ;
}void dfs ( int u ) {get_siz ( u ) ;node_num = siz[u] ;root = 0 ;get_root ( u ) ;int rt = root ;vis[rt] = 1 ;travel ( e , H , rt ) {int v = e -> v ;if ( !vis[v] ) dfs ( v ) ;}++ dep ;travel ( e , H , rt ) {int v = e -> v ;if ( vis[v] ) continue ;cnt = 0 ;get_path ( v , val[v] % MOD ) ;rep ( i , 0 , cnt ) {int tmp = ( LL ) val[rt] * path[i].c % MOD ;if ( tmp == K ) update_ans ( rt , path[i].idx ) ;int x = ( LL ) K * ni[tmp] % MOD ;if ( flag[x] == dep ) update_ans ( best[x] , path[i].idx ) ;}rep ( i , 0 , cnt ) {int c = path[i].c , idx = path[i].idx ;if ( flag[c] != dep || best[c] > idx ) {best[c] = idx ;flag[c] = dep ;}}}vis[rt] = 0 ;
}void solve () {int x , y , c ;clear () ;FOR ( i , 1 , n ) scanf ( "%d" , &val[i] ) ;rep ( i , 1 , n ) {scanf ( "%d%d" , &x , &y ) ;addedge ( x , y ) ;addedge ( y , x ) ;}dfs ( 1 ) ;if ( ans[0] != INF ) printf ( "%d %d\n" , ans[0] , ans[1] ) ;else printf ( "No solution\n" ) ;
}int main () {rep ( i , 0 , MOD ) ni[i] = pow ( i , MOD - 2 ) ;while ( ~scanf ( "%d%d" , &n , &K ) ) solve () ;return 0 ;
}




这篇关于【HDU】4812 D Tree 点分治的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1139260

相关文章

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

hdu 2093 考试排名(sscanf)

模拟题。 直接从教程里拉解析。 因为表格里的数据格式不统一。有时候有"()",有时候又没有。而它也不会给我们提示。 这种情况下,就只能它它们统一看作字符串来处理了。现在就请出我们的主角sscanf()! sscanf 语法: #include int sscanf( const char *buffer, const char *format, ... ); 函数sscanf()和

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

hdu 1754 I Hate It(线段树,单点更新,区间最值)

题意是求一个线段中的最大数。 线段树的模板题,试用了一下交大的模板。效率有点略低。 代码: #include <stdio.h>#include <string.h>#define TREE_SIZE (1 << (20))//const int TREE_SIZE = 200000 + 10;int max(int a, int b){return a > b ? a :

hdu 1166 敌兵布阵(树状数组 or 线段树)

题意是求一个线段的和,在线段上可以进行加减的修改。 树状数组的模板题。 代码: #include <stdio.h>#include <string.h>const int maxn = 50000 + 1;int c[maxn];int n;int lowbit(int x){return x & -x;}void add(int x, int num){while

hdu 3790 (单源最短路dijkstra)

题意: 每条边都有长度d 和花费p,给你起点s 终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。 解析: 考察对dijkstra的理解。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstrin

hdu 2489 (dfs枚举 + prim)

题意: 对于一棵顶点和边都有权值的树,使用下面的等式来计算Ratio 给定一个n 个顶点的完全图及它所有顶点和边的权值,找到一个该图含有m 个顶点的子图,并且让这个子图的Ratio 值在所有m 个顶点的树中最小。 解析: 因为数据量不大,先用dfs枚举搭配出m个子节点,算出点和,然后套个prim算出边和,每次比较大小即可。 dfs没有写好,A的老泪纵横。 错在把index在d

hdu 1102 uva 10397(最小生成树prim)

hdu 1102: 题意: 给一个邻接矩阵,给一些村庄间已经修的路,问最小生成树。 解析: 把已经修的路的权值改为0,套个prim()。 注意prim 最外层循坏为n-1。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstri

hdu 1285(拓扑排序)

题意: 给各个队间的胜负关系,让排名次,名词相同按从小到大排。 解析: 拓扑排序是应用于有向无回路图(Direct Acyclic Graph,简称DAG)上的一种排序方式,对一个有向无回路图进行拓扑排序后,所有的顶点形成一个序列,对所有边(u,v),满足u 在v 的前面。该序列说明了顶点表示的事件或状态发生的整体顺序。比较经典的是在工程活动上,某些工程完成后,另一些工程才能继续,此时