题目描述
司令部截获了深海的电报,你的镇守府即将被深海轰炸。
虽然你作为历战提督,已经有了很多局地战、火箭机,但是刚刚击破 E6 甲,拥有亚特兰大以及最高倍率对空 ci 的你,决定只用亚特兰大抵挡对面的炸家。
你的镇守府可以看成一棵树,深海的轰炸是在某两个点之间进行的(起点终点交换视为一种),轰炸路径是树上的简单路径。也就是说,深海一共有 种可能的轰炸方案。
你的亚特兰大在不同的边上具有不同的击坠值,最终深海剩下的飞机数是经过路径上所有击坠值的gcd − 1。当这个值变成 0 时,你就成功抵挡住了深海的炸家。
现在你想知道,深海一共有多少种可能的轰炸方案,你可以成功抵挡。
但不幸的是,亚特兰大初来乍到,击坠值有点不稳定,所以会出现 Q 次击坠值变化,每次变化指某一条边的击坠值改变。
请你计算出这 Q + 1 种局面的所有答案。
对于所有数据,满足 2 ≤ n ≤ 10^5 , Q ≤ 100 , 1 ≤ w,x ≤ 10^6 。
题解
显然的反演,设f(x)表示路径长度为x的倍数的路径条数:
\(ans=\sum{f(x)\mu(x)}\)
于是有及其暴力的做法,直接LCT维护子树大小,修改只会修改约数棵LCT(经过这条边的)
其实Q<=100,所以有更暴力的做法:
把非修改的边的块缩一下后用可撤销并查集维护,每次暴力加/删Q*约数条边(准确来说是2^质因子,其他的μ=0)
然后我在建新点时map被卡了,于是发现可以直接暴力维护每个点相连的边的质因子,每个点可能的质因子不超200个
code
#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define mod 10000007
#define ll long long
#define file
using namespace std;
int a[100001][3],b[100001][129][3],B[100001][2],fa[3000001],d[3000001];
int size[3000001],num[100001],Num[101],Tot[100001],n,i,j,k,l,Q,tot,len;
int A[100001][8],C[100001][201][2],c2[100001];
bool bz[100001],Bz;
ll ans;
void fj(register int t,int id)
{
int i,j,k,l,s;
Tot[id]=0;
s=floor(sqrt(t));
fo(i,2,s)
if (!(t%i))
{
while (!(t%i)) t/=i;
A[id][++Tot[id]]=i;
}
if (t>1) A[id][++Tot[id]]=t;
}
int pd(int t,int c)
{
int i;
fo(i,1,c2[t]) if (C[t][i][0]==c) return C[t][i][1];
++c2[t],C[t][c2[t]][0]=c;C[t][c2[t]][1]=++len;
return -len;
}
int gf(register int t) {if (fa[t]==t) return t;return gf(fa[t]);}
int Gf(register int t) {if (fa[t]==t) return t;fa[t]=gf(fa[t]); return fa[t];}
int get(int c,int t) {int s=pd(t,c); if (s<0) {fa[len]=len;d[len]=1;size[len]=1; return len;} return s;}
void link(int t,int T,int c,int id,int s)
{
int i,x,y;
if (T>Tot[t])
{
if (!Bz)
x=gf(get(c,a[t][0])),y=gf(get(c,a[t][1]));
else
x=Gf(get(c,a[t][0])),y=Gf(get(c,a[t][1]));
if (d[x]>d[y]) swap(x,y);
if (d[x]==d[y]) b[t][id][2]=1; else b[t][id][2]=0;
b[t][id][0]=x;b[t][id][1]=y;
fa[x]=y;d[y]+=b[t][id][2];ans+=1ll*size[x]*size[y]*s;size[y]+=size[x];
return;
}
link(t,T+1,c,id*2,s);
link(t,T+1,c*A[t][T],id*2+1,-s);
}
void cut(int t,int T,int c,int id,int s)
{
int i,x,y;
if (T>Tot[t])
{
x=b[t][id][0],y=b[t][id][1];
fa[x]=x;d[y]-=b[t][id][2];size[y]-=size[x];ans-=1ll*size[x]*size[y]*s;
return;
}
cut(t,T+1,c,id*2,s);
cut(t,T+1,c*A[t][T],id*2+1,-s);
}
void js()
{
int i;
fo(i,1,tot) link(Num[i],1,1,1,1);
printf("%lld\n",ans);
fd(i,tot,1) cut(Num[i],1,1,1,1);
}
int main()
{
freopen("atoranta.in","r",stdin);
#ifdef file
freopen("atoranta.out","w",stdout);
#endif
scanf("%d",&n);
fo(i,1,n-1) scanf("%d%d%d",&a[i][0],&a[i][1],&a[i][2]),fj(a[i][2],i);
scanf("%d",&Q);
fo(i,1,Q) scanf("%d%d",&B[i][0],&B[i][1]),bz[B[i][0]]=1;
Bz=1;
fo(i,1,n-1)
if (bz[i])
num[i]=++tot,Num[tot]=i;
else
link(i,1,1,1,1);
fo(i,1,len) gf(i),d[i]=fa[i]==i?2:1;
Bz=0;
js();
fo(i,1,Q)
a[B[i][0]][2]=B[i][1],fj(B[i][1],B[i][0]),js();
fclose(stdin);
fclose(stdout);
return 0;
}