• codechef TREECNT2


    (gcd(l...r))表示(l...r)路径上的(gcd)
    (ans=[gcd(l...r)]=sum_{d|gcd(l...r)}vu(d))
    (=sum_{i=1}^{1000000}vu(d)sum_{d|gcd(l...r)}1)
    一个显然的想法:注意到只有(vu(d) eq 0)且被一个(gcd(l...r))整除的(d)才有用。
    所以可以把所有(gcd(l...r))的约数(d)拿出来,建立一新树(T'),把边权为(d)的倍数的边插入(T'),然后统计每个连通块大小的二次方和。
    由于最多会插入(2^d)条边,所以一次询问(O(n2^d))
    有修改的情况显然可以维护(1000000)个LCT,然后在修改边权后在LCT上link,cut(2^d)次。
    由于直接维护这么多个LCT不可承受,所以可以再次离线,枚举每个LCT,执行操作,再累加答案。
    然而问题并没有要求强制在线。
    这种有连通块的题,显然考虑并查集维护。
    考虑可撤销并查集。
    有一些边没有被修改过,显然先插入进去。
    注意到(Q)很小。
    每次修改时提取出在其他询问中被修改的边,插入它在当前位置的值,然后把当前位置的边插入到数据结构中。
    最后再撤销。
    最终时间复杂度(n2^d+2^d*Q^2*log_2n)

    #include<bits/stdc++.h>
    using namespace std;
    #define N 2000010
    #define M 2000010
    #define int long long
    int n,a[N],b[N],c[N],q,pr[M],f[N],sz[N],fc[N],vv[N],va[N],vg,vt[N],tp,k[N],x[N],cv[N],vp[N];
    int p[M],vi[M],ct,vu[M];
    int fd(int x){
    	while(f[x])
    		x=f[x];
    	return x; 
    }
    struct no{
    	int s,f,x,y;
    }ss[M];
    int mg(int x,int y){
    	x=fd(x);
    	y=fd(y);
    	if(x==y)
    		return 0;
    	if(sz[x]>sz[y])
    		swap(x,y);
    	int ans=sz[x]*sz[y];
    	ss[++tp]=((no){sz[y],f[x],x,y});
    	sz[y]+=sz[x];
    	f[x]=y;
    	return ans;
    }
    void rb(int x){
    	while(tp>x){
    		no z=ss[tp];
    		f[z.x]=z.f;
    		sz[z.y]=z.s;
    		tp--;
    	}
    }
    vector<int>vc[M];
    void si(){
    	vu[1]=1;
    	for(int i=2;i<M;i++){
    		if(!vi[i]){
    			p[++ct]=i;
    			vu[i]=-1;
    			pr[i]=i;
    		}
    		for(int j=1;i*p[j]<M;j++){
    			vi[i*p[j]]=1;
    			pr[i*p[j]]=p[j];
    			if(i%p[j]==0)
    				break;
    			vu[i*p[j]]=-vu[i];
    		}
    	}
    }
    void dfs(int v,int x,int y,int t){
    	if(y==ct+1){
    		if(!t)
    			vp[v]++;
    		cv[v]++;
    		if(t)
    			vc[v].push_back(x);
    		return;
    	}
    	dfs(v*fc[y],x,y+1,t);
    	dfs(v,x,y+1,t);
    }
    signed main(){
    	freopen("atoranta.in","r",stdin);
    	freopen("atoranta.out","w",stdout);
    	si();
    	memset(vi,0,sizeof(vi));
    	scanf("%lld",&n);
    	for(int i=1;i<n;i++)
    		scanf("%lld%lld%lld",&a[i],&b[i],&c[i]);
    	for(int i=1;i<=n;i++)
    		sz[i]=1;
    	for(int i=1;i<n;i++){
    		ct=0;
    		int x=c[i];
    		while(x!=1){
    			if(!vv[pr[x]])
    				fc[++ct]=pr[x];
    			vv[pr[x]]=1;
    			x/=pr[x];
    		}
    		dfs(1,i,1,1);
    		for(int j=1;j<=ct;j++)
    			vv[fc[j]]=0;
    	}
    	int ans=0;
    	for(int i=1;i<=n;i++)
    		sz[i]=1;
    	for(int i=1;i<M;i++)
    		if(vc[i].size()&&vu[i]){
    			for(int j=0;j<vc[i].size();j++)
    				ans+=vu[i]*mg(a[vc[i][j]],b[vc[i][j]]);
    			rb(0);
    		}
    	printf("%lld
    ",ans);
    	scanf("%lld",&q);
    	for(int i=1;i<=q;i++){
    		scanf("%lld%lld",&k[i],&x[i]);
    		ct=0;
    		int y=x[i];
    		while(y!=1){
    			if(!vv[pr[y]])
    				fc[++ct]=pr[y];
    			vv[pr[y]]=1;
    			y/=pr[y];
    		}
    		for(int j=1;j<=ct;j++)
    			vv[fc[j]]=0;
    		dfs(1,i,1,0);
    		vi[k[i]]=1;
    	}
    	for(int i=1;i<=n;i++)
    		if(vi[i]){
    			ct=0;
    			int y=c[i];
    			while(y!=1){
    				if(!vv[pr[y]])
    					fc[++ct]=pr[y];
    				vv[pr[y]]=1;
    				y/=pr[y];
    			}
    			for(int j=1;j<=ct;j++)
    				vv[fc[j]]=0;
    			dfs(1,i,1,0);
    		}
    	ans=0;
    	int ct=0,ok=0;
    	for(int i=1;i<M;i++){
    		if(cv[i]&&vu[i]){
    			ct+=q*q;
    			ans=0;
    			for(int j=0;j<vc[i].size();j++)
    				if(!vi[vc[i][j]])
    					ans+=vu[i]*mg(a[vc[i][j]],b[vc[i][j]]);
    			for(int j=1;j<=q;j++)
    				va[j]+=ans;
    			int tt=tp;
    			for(int j=1;j<=q;j++)
    				vt[k[j]]=c[k[j]];
    			if(vp[i]){
    				for(int j=1;j<=q;j++){
    					vt[k[j]]=x[j];
    					ans=0;
    					for(int l=1;l<=q;l++)
    						if(vt[k[l]]%i==0){
    							ok=1;
    							ans+=vu[i]*mg(a[k[l]],b[k[l]]);
    						}
    					rb(tt);
    					va[j]+=ans;
    				}
    			}
    			rb(0);
    		}
    	}
    	//printf("%d
    ",ok);
    	for(int i=1;i<=q;i++)
    		printf("%lld
    ",va[i]);
    }
    
  • 相关阅读:
    封装LuaEngine
    Lua for循环
    lua 排序
    Lua中的数学库
    linux 常用指令
    lua table 遍历
    Charles——charles代理菜单proxy总结——端口转发
    Charles——charles代理菜单proxy总结—— 开始/暂停模拟慢网速—— stop/start throttling 和 throttling settings
    Charles——charles代理菜单proxy总结——代理设置proxy setting
    Charles——charles代理菜单proxy总结——SSL代理设置SSL Proxying Srtting
  • 原文地址:https://www.cnblogs.com/ctmlpfs/p/14092130.html
Copyright © 2020-2023  润新知