给定一棵 n 个点的树,每条边有个正整数边权。有 q 次修改操作,每次会修改一条边的边权。
在所有修改前以及每次修改后,你需要求出有多少个无序点对满足它们之间的最短路径上所有边权的最大公约数=1。
最大公约数=1看似很恶心。
考虑莫比乌斯函数,则k|gcd的答案很好求。两点之间如果用边权是k的倍数的边相连,那么就将它们连起来。
观察数据范围,暴力1e6*128即可得出每个数的约数了。
这个操作咋搞?
按秩合并。
就是每个点有一个秩rank[x],合并的时候,让rank小的合并到rank大的去。
在这道题目中,如果rank[x]=rank[y],那么让x连到y去,然后rank[y]++即可。
要再开一个vector,存下修改的时间和修改后的新边的信息。
这个咋办?开个数组表示现在第x条边对应的最新的信息在q个询问中的哪里就好了。
#include
#include
#include
#include
#include
#include
#define N 100010
#define M 1000010
#define LL long long
#define P(a) putchar(a)
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
struct note{
int to,next,val;
};note edge[N*2];
struct note1{
int x,y,z;
};note1 a[N*2],qu[N],St[N];
int tot,head[N];
int i,j,k,l,n,m,q,top,cnt;
LL Ans[N],tag,temp;
int u,v,w,x,gx,gy,_2[10];
int ys[M][10];
int dep[N],fa[N],rank[N];
int o[N],tar[N],mu[M],pri[N];
LL siz[N];
bool bz[M],Bz[N];
vector<int>vec1[M];
vector< pair<int,int> >vec2[M];
int read(){
int fh=1,rs=0;char ch;
while((ch<'0'||ch>'9')&&(ch^'-'))ch=getchar();
if(ch=='-')fh=-1,ch=getchar();
while(ch>='0'&&ch<='9')rs=(rs<<3)+(rs<<1)+(ch^'0'),ch=getchar();
return fh*rs;
}
void write(LL x){if(x>9)write(x/10);P(x%10+'0');}
void get_prime(){
int i,j,k;
mu[1]=1;
fo(i,2,M-10){
if(!bz[i]){
pri[++pri[0]]=i;
mu[i]=-1;
ys[i][ys[i][0]=1]=i;
}
fo(j,1,pri[0]){
k=i*pri[j];
if(k>M-10)break;
bz[k]=1;
memcpy(ys[k],ys[i],sizeof(ys[k]));
if(i%pri[j]==0){
mu[k]=0;
break;
}else{
ys[k][++ys[k][0]]=pri[j];
mu[k]=-mu[i];
}
}
}
}
void get1(){
int i,j,k,l,temp;
fo(i,1,n-1)if(!Bz[i]){
fo(j,0,_2[ys[a[i].z][0]+1]-1){
temp=1;
fo(k,1,ys[a[i].z][0])if(j&_2[k])temp=temp*ys[a[i].z][k];
vec1[temp].push_back(i);
}
}
fo(i,1,o[0])tar[o[i]]=o[i];
fo(i,0,q){
if(i)tar[qu[i].x]=i+n-1;
fo(j,1,o[0]){
x=tar[o[j]];
fo(k,0,_2[ys[a[x].z][0]+1]-1){
temp=1;
fo(l,1,ys[a[x].z][0])if(k&_2[l])temp=temp*ys[a[x].z][l];
vec2[temp].push_back(make_pair(i,x));
}
}
}
}
int get(int x){
while(fa[x])x=fa[x];
return x;
}
LL calc(LL x){
return x*(x-1)>>1;
}
void merge(int x,int y){
if(rank[x]>=rank[y])swap(x,y);
fa[x]=y;
temp-=calc(siz[x])+calc(siz[y]);
siz[y]+=siz[x];
temp+=calc(siz[y]);
St[++top].x=x;
St[top].y=y;
St[top].z=rank[y];
if(rank[y]==rank[x])rank[y]++;
}
void ctrl_z(){
int x=St[top].x,y=St[top].y;
fa[x]=0;
temp-=calc(siz[y]);
siz[y]-=siz[x];
temp+=calc(siz[x])+calc(siz[y]);
rank[y]=St[top].z;
top--;
}
int main(){
get_prime();
_2[1]=1;fo(i,2,9)_2[i]=_2[i-1]*2;
n=read();
fo(i,1,n-1)a[i].x=read(),a[i].y=read(),a[i].z=read();
q=read();
fo(i,1,q){
qu[i].x=read();qu[i].y=read();
a[i+n-1]=a[qu[i].x];
a[i+n-1].z=qu[i].y;
if(!Bz[qu[i].x]){
Bz[qu[i].x]=1;
o[++o[0]]=qu[i].x;
}
}
get1();
fo(i,1,n)siz[i]=1;
fo(i,1,M-10)if(mu[i]!=0){
if(vec1[i].size()){
temp=0;
fo(j,0,vec1[i].size()-1){
x=vec1[i][j];
gx=get(a[x].x);
gy=get(a[x].y);
if(gx^gy)merge(gx,gy);
}
tag+=temp*mu[i];
}
temp=0;
cnt=0;
if(vec2[i].size()){
fo(j,0,vec2[i].size()-1){
if(vec2[i][j].first!=vec2[i][j-1].first&&j){
Ans[vec2[i][j-1].first]+=mu[i]*temp;
fo(k,1,cnt)ctrl_z();
cnt=0;
}
cnt++;
gx=get(a[vec2[i][j].second].x);
gy=get(a[vec2[i][j].second].y);
if(gx^gy)merge(gx,gy);
}
Ans[vec2[i][j-1].first]+=mu[i]*temp;
fo(k,1,cnt)ctrl_z();
}
while(top)ctrl_z();
}
fo(i,0,q)write(Ans[i]+tag),P('\n');
return 0;
}