题目大意
给定一个
n
个点的树,树上每条边都有一个权值
求每次修改后的图中特征值为1的路径数量。
Data Constraint
题解
设
f(i)
表示特征值是
i
的倍数的路径数量。那么
现在问题转化成求 f(i) .
对于每一条边,我们可以求出它作用的时间段,然后每条边都预处理,将编号挂在对应可贡献的约数上,这个可以用vector实现。
反演的时候,每次枚举一个约数 d ,先将没被修改的边加入图中,然后枚举时刻
SRC
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std ;
#define N 100000 + 10
#define M 1000000 + 10
typedef long long ll ;
struct Edge {
int u , v , w ;
} E[N] ;
struct Note {
int h , w , l , r ;
} a[2*N] ;
vector < int > Que[M] ;
bool flag[M] ;
int Pri[M] , Miu[M] , P[M] ;
int fa[N] , Rank[N] , Size[N] ;
int tp[N] , last[N] , S[M] ;
int n , Q , Cnt , top ;
ll Ans[N] , ans ;
void Pre() {
Miu[1] = 1 ;
for (int i = 2 ; i < M ; i ++ ) {
if ( !flag[i] ) {
Pri[++Pri[0]] = i ;
Miu[i] = -1 ;
P[i] = i ;
}
for (int j = 1 ; j <= Pri[0] ; j ++ ) {
if ( 1ll * i * Pri[j] >= M ) break ;
flag[i*Pri[j]] = 1 ;
P[i*Pri[j]] = Pri[j] ;
if ( i % Pri[j] == 0 ) { Miu[i*Pri[j]] = 0 ; break ; }
Miu[i*Pri[j]] = -Miu[i] ;
}
}
}
void DFS( int k , int s , int h ) {
if ( k > tp[0] ) {
Que[s].push_back( h ) ;
return ;
}
DFS( k + 1 , s , h ) ;
DFS( k + 1 , s * tp[k] , h ) ;
}
int Get( int x ) { return fa[x] == x ? x : Get( fa[x] ) ; }
void Union( int x , int y ) {
int fx = Get(x) ;
int fy = Get(y) ;
if ( fx == fy ) return ;
if ( Rank[fx] > Rank[fy] ) swap( fx , fy ) ;
S[++top] = fx ;
fa[fx] = fy ;
if ( Rank[fx] == Rank[fy] ) {
Rank[fy] ++ ;
S[++top] = -fy ;
}
ans += (ll)Size[fx] * Size[fy] ;
Size[fy] += Size[fx] ;
}
void ReSet( int t ) {
while ( top > t ) {
if ( S[top] > 0 ) {
int fy = fa[S[top]] ;
fa[S[top]] = S[top] ;
Size[fy] -= Size[S[top]] ;
ans -= (ll)Size[fy] * Size[S[top]] ;
} else {
Rank[-S[top]] -- ;
}
top -- ;
}
}
int main() {
Pre() ;
scanf( "%d" , &n ) ;
for (int i = 1 ; i <= n ; i ++ ) {
fa[i] = i , Rank[i] = Size[i] = 1 ;
}
for (int i = 1 ; i < n ; i ++ ) scanf( "%d%d%d" , &E[i].u , &E[i].v , &E[i].w ) ;
scanf( "%d" , &Q ) ;
Cnt = Q ;
for (int i = 1 ; i <= Q ; i ++ ) {
scanf( "%d%d" , &a[i].h , &a[i].w ) ;
if ( !last[a[i].h] ) {
++ Cnt ;
a[Cnt].h = a[i].h ;
a[Cnt].w = E[a[i].h].w ;
a[Cnt].l = 0 ;
a[Cnt].r = i - 1 ;
} else a[last[a[i].h]].r = i - 1 ;
a[i].l = i ;
last[a[i].h] = i ;
}
for (int i = 1 ; i < n ; i ++ ) {
if ( last[i] ) {
a[last[i]].r = Q ;
continue ;
}
int x = E[i].w ;
tp[0] = 0 ;
while ( x > 1 ) {
int d = P[x] ;
tp[++tp[0]] = d ;
while ( x % d == 0 ) x /= d ;
}
DFS( 1 , 1 , i ) ;
}
for (int i = 1 ; i <= Cnt ; i ++ ) {
int x = a[i].w ;
tp[0] = 0 ;
while ( x > 1 ) {
int d = P[x] ;
tp[++tp[0]] = d ;
while ( x % d == 0 ) x /= d ;
}
DFS( 1 , 1 , n + i ) ;
}
for (int i = 1 ; i <= 1000000 ; i ++ ) {
if ( Que[i].size() == 0 || !Miu[i] ) continue ;
int st = n + Cnt + 1 ;
top = ans = 0 ;
for (int j = 0 ; j < (signed) Que[i].size() ; j ++ ) {
int now = Que[i][j] ;
if ( now > n ) {
st = j ;
break ;
}
Union( E[now].u , E[now].v ) ;
}
int Ori = top ;
for (int tim = 0 ; tim <= Q ; tim ++ ) {
for (int j = st ; j < (signed) Que[i].size() ; j ++ ) {
int now = Que[i][j] ;
if ( a[now-n].l <= tim && a[now-n].r >= tim ) Union( E[a[now-n].h].u , E[a[now-n].h].v ) ;
}
Ans[tim] += (ll)Miu[i] * ans ;
ReSet( Ori ) ;
}
ReSet(0) ;
}
for (int i = 0 ; i <= Q ; i ++ ) printf( "%lld\n" , Ans[i] ) ;
return 0 ;
}
以上.