点分治
处理树上问题,将问题范围分为穿过树根的与子树内部
对于子树内部采用递归处理,对穿过树根具体题目具体分析
为了让递归层数尽量少,先要找重心
找重心:
重心为所有子树的最大值最小的节点
用
s
z
[
i
]
sz[i]
sz [ i ] 记录点
i
i
i 作为父亲子树时的子树数量,每次从父节点到
i
i
i 节点时初始化为
1
1
1
用
m
a
x
_
s
z
[
i
]
max\_sz[i]
ma x _ sz [ i ] 记录节点最大的子树数量,递归处理完所有子树后,用
a
l
l
−
s
z
[
i
]
all-sz[i]
a ll − sz [ i ] 更新
m
a
x
_
s
z
[
i
]
max\_sz[i]
ma x _ sz [ i ] 即可得到
i
i
i 节点的最大子树节点数量,再更新
z
x
zx
z x 即可
分治:找重心,计算经过重心的可能性,遍历以重心为根的子树,对那些子树找重心继续递归
# include <bits/stdc++.h>
using namespace std;
const int N = 2e4 + 10 , M = 1e2 + 10 ;
const int INF = 1e7 + 10 ;
bool vis[ N] , able[ M] ;
int n, m, zx, idx;
int zs[ N] , max_zs[ N] , ask[ M] ;
int d[ N] , dis[ N] ;
bool judge[ INF] ;
struct edge {
int v, w;
edge* nex;
} ed[ N* 2 ] ;
int ptop;
edge* head[ N] ;
void add ( int u, int v, int w) {
ed[ ptop] . v = v;
ed[ ptop] . w = w;
ed[ ptop] . nex = head[ u] ;
head[ u] = & ed[ ptop] ;
ptop++ ;
}
void get ( ) {
cin >> n >> m;
for ( int i = 1 ; i <= n - 1 ; i++ ) {
int u, v, w; cin >> u >> v >> w;
add ( u, v, w) ;
add ( v, u, w) ;
}
for ( int i = 1 ; i <= m; i++ )
cin >> ask[ i] ;
}
void get_zx ( int u, int fa, int all) {
zs[ u] = 1 ;
max_zs[ u] = 0 ;
for ( edge* p = head[ u] ; p != NULL ; p = p -> nex) {
int v = p -> v;
if ( vis[ v] || v == fa) continue ;
get_zx ( v, u, all) ;
zs[ u] += zs[ v] ;
max_zs[ u] = max ( max_zs[ u] , zs[ v] ) ;
}
max_zs[ u] = max ( all - zs[ u] , max_zs[ u] ) ;
if ( max_zs[ u] < max_zs[ zx] )
zx = u;
}
void get_dis ( int u, int fa, int len) {
d[ ++ idx] = len;
for ( edge* p = head[ u] ; p != NULL ; p = p -> nex) {
int v = p -> v, w = p -> w;
if ( vis[ v] || v == fa) continue ;
get_dis ( v, u, len + w) ;
}
}
void calc ( int x) {
judge[ 0 ] = 1 ;
stack< int > st;
for ( edge* p = head[ x] ; p != NULL ; p = p -> nex) {
int v = p -> v, w = p -> w;
if ( vis[ v] ) continue ;
idx = 0 ;
get_dis ( v, x, w) ;
for ( int i = 1 ; i <= idx; i++ ) {
for ( int j = 1 ; j <= m; j++ ) {
if ( ask[ j] - d[ i] >= 0 && ask[ j] - d[ i] < INF && judge[ ask[ j] - d[ i] ] )
able[ j] = 1 ;
}
}
for ( int i = 1 ; i <= idx; i++ )
{
if ( d[ i] <= INF) {
judge[ d[ i] ] = 1 ;
st. push ( d[ i] ) ;
}
}
}
while ( ! st. empty ( ) ) {
judge[ st. top ( ) ] = 0 ;
st. pop ( ) ;
}
}
void divid ( int x) {
calc ( x) ;
vis[ x] = 1 ;
for ( edge* p = head[ x] ; p != NULL ; p = p -> nex) {
int v = p -> v;
if ( vis[ v] ) continue ;
zx = 0 ;
get_zx ( v, x, zs[ v] ) ;
divid ( zx) ;
}
}
int main ( ) {
ios:: sync_with_stdio ( false ) ;
get ( ) ;
zx = 0 ;
max_zs[ 0 ] = INF;
get_zx ( 1 , 0 , n) ;
divid ( zx) ;
for ( int i = 1 ; i <= m; i++ ) {
if ( able[ i] )
cout << "AYE" << endl;
else
cout << "NAY" << endl;
}
}
找所有3倍数的连接(包括本身,ab与ba不同)
正常分治,calc时记录0,1,2的数量即可
# include <bits/stdc++.h>
using namespace std;
# define ll long long
const int N = 2e4 + 10 , INF = 1e9 + 10 ;
ll gcd ( ll a, ll b) {
if ( b == 0 ) return a;
else return gcd ( b, a% b) ;
}
ll n;
bool vis[ N] ;
int zs[ N] , max_zs[ N] , zx;
struct edge {
int v, w;
edge* nex;
} ed[ N* 2 ] ;
int ptop;
edge* head[ N] ;
void add ( int u, int v, int w) {
ed[ ptop] . v = v;
ed[ ptop] . nex = head[ u] ;
ed[ ptop] . w = w;
head[ u] = & ed[ ptop++ ] ;
}
void get_zx ( int u, int fa, int all) {
zs[ u] = 1 ;
max_zs[ u] = 0 ;
for ( edge* p = head[ u] ; p != NULL ; p = p -> nex) {
int v = p -> v;
if ( vis[ v] || v == fa) continue ;
get_zx ( v, u, all) ;
zs[ u] += zs[ v] ;
max_zs[ u] = max ( max_zs[ u] , zs[ v] ) ;
}
max_zs[ u] = max ( max_zs[ u] , all - zs[ u] ) ;
if ( max_zs[ zx] > max_zs[ u] )
zx = u;
}
ll num[ 3 ] , d[ 3 ] , ans;
void get_dis ( int u, int fa, int len) {
d[ len] ++ ;
for ( edge* p = head[ u] ; p != NULL ; p = p -> nex) {
int v = p -> v, w = p -> w;
if ( vis[ v] || v == fa) continue ;
get_dis ( v, u, ( len + w) % 3 ) ;
}
}
void calc ( int u) {
num[ 1 ] = num[ 2 ] = 0 ;
num[ 0 ] = 1 ;
for ( edge* p = head[ u] ; p != NULL ; p = p -> nex) {
int v = p -> v, w = p -> w;
if ( vis[ v] ) continue ;
d[ 0 ] = d[ 1 ] = d[ 2 ] = 0 ;
get_dis ( v, u, w % 3 ) ;
for ( int i = 0 ; i < 3 ; i++ )
ans += num[ ( 3 - i) % 3 ] * d[ i] ;
for ( int i = 0 ; i < 3 ; i++ )
num[ i] += d[ i] ;
}
}
void divid ( int u) {
calc ( u) ;
vis[ u] = 1 ;
for ( edge* p = head[ u] ; p != NULL ; p = p -> nex) {
int v = p -> v;
if ( vis[ v] ) continue ;
zx = 0 ;
get_zx ( v, u, zs[ v] ) ;
divid ( zx) ;
}
}
void get ( ) {
cin >> n;
for ( int i = 1 ; i <= n - 1 ; i++ ) {
int u, v, w; cin >> u >> v >> w;
w %= 3 ;
add ( u, v, w) ;
add ( v, u, w) ;
}
}
int main ( ) {
max_zs[ 0 ] = INF;
get ( ) ;
zx = 0 ;
get_zx ( 1 , 0 , n) ;
divid ( zx) ;
ll all = n* n;
ans = ans * 2 + n;
ll gc = gcd ( ans, all) ;
cout << ans / gc << '/' << all / gc << endl;
}