6570. 亚特兰大 (atoranta)

题目描述

司令部截获了深海的电报,你的镇守府即将被深海轰炸。
虽然你作为历战提督,已经有了很多局地战、火箭机,但是刚刚击破 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;
}

猜你喜欢

转载自www.cnblogs.com/gmh77/p/12758026.html