清华集训2014 奇数国

  • 【清华集训2014】奇数国
  • 欧拉函数+线段树,傻逼题……。
  • 首先那个\(ax+by=1\)就是在搞笑,想一想有整数的条件就是\(gcd(a,b)=1\),实际上是让你求\(\phi\)
  • 所以现在需要支持两种操作,区间积求\(phi\),单点修改。
  • 因为每个数都只有最多\(60\)个不同质因子,所以可以把它分解质因数。
  • 然后就能用\(60\)个线段树来维护每个质因子个数。
  • 询问是求区间乘积的欧拉函数,然后用公式\(\phi_n=n*\prod(1-\frac {1}{p_i})\)就可以了。
  • 复杂度\(O(60*qlogn)\)
  • 线段树可以换成树状数组,常数小很多。
#include<bits/stdc++.h>
#define R register int
#define db double
#define ll long long 
using namespace std;
const int N=100001;
const int mod=19961993;
int n,m,op,u,v,ans;
int gi(){
    R x=0,k=1;char c=getchar();
    while(c!='-'&&(c<'0'||c>'9'))c=getchar();
    if(c=='-')k=-1,c=getchar();
    while(c<='9'&&c>='0')x=(x<<3)+(x<<1)+c-'0',c=getchar();
    return x*k;
}
namespace cpp1{
	int tot,mk[N],prm[N];
	struct mon{
		int s[61];
		void init(){memset(s,0,sizeof(s));}
	}te[N*4],nw;
	int Qpow(R x,R y){
		R ans=1,bas=x;
		while(y){
			if(y&1)ans=1ll*ans*bas%mod;
			bas=1ll*bas*bas%mod,y>>=1;
		}return ans;
	}
	mon mul(mon x,mon y){
		mon z;
		for(R i=1;i<=60;++i)z.s[i]=x.s[i]+y.s[i];
		return z;
	}
	mon rev(R x){
		mon z;z.init();
		for(R j=1;j<=tot;++j){
			while(x%prm[j]==0)
				z.s[j]++,x/=prm[j];
		}
		return z;
	}
	void init(){
		mk[0]=mk[1]=1;
		for(R i=2;i<N;++i){
			if(!mk[i])prm[++tot]=i;
			for(R j=1;j<=tot&&i*prm[j]<N;++j){
				mk[i*prm[j]]=1;
				if(i%prm[j]==0)break;
			}
		}tot=60;
	}
	void upd(R Le,R Ri,R ps,R i){
		if(Le==Ri){te[i]=nw;return ;}
		R mid=(Le+Ri)>>1,ls=(i<<1),rs=(ls|1);
		if(ps<=mid)upd(Le,mid,ps,ls);else upd(mid+1,Ri,ps,rs);
		te[i]=mul(te[ls],te[rs]);
	}
	mon query(R Le,R Ri,R le,R ri,R i){
		if(Le==le&&Ri==ri)return te[i];
		R mid=(Le+Ri)>>1,ls=(i<<1),rs=(ls|1);
		if(ri<=mid)return query(Le,mid,le,ri,ls);
		else if(le>mid)return query(mid+1,Ri,le,ri,rs);
		else return mul(query(Le,mid,le,mid,ls),query(mid+1,Ri,mid+1,ri,rs));
	}
	void Main(){
		n=100000,m=gi(),init(),nw.init(),nw.s[2]=1;
		for(R i=1;i<=n;++i)upd(1,n,i,1);
		while(m--){
			op=gi(),u=gi(),v=gi();
			if(op==1)nw=rev(v),upd(1,n,u,1);
			else {
				nw=query(1,n,u,v,1),ans=1;
				for(R j=1;j<=60;++j)
					if(nw.s[j]){
						ans=1ll*ans*(prm[j]-1)%mod;
						ans=1ll*ans*Qpow(prm[j],nw.s[j]-1)%mod;
					}
				printf("%d\n",ans);
			}
		}
	}
}
int main(){
	cpp1::Main();
    return 0;
}

posted @ 2018-12-02 17:03  Tyher  阅读(156)  评论(0编辑  收藏  举报