bzoj3813 奇数国

Description

在一片美丽的大陆上有(100000)个国家,记为(1)(100000)。这里经济发达,有数不尽的账房,并且每个国家有一个银行。
某大公司的领袖在这(100000)个银行开户时都存了(3)大洋,他惜财如命,因此会不时地派小弟 GFS 清点一些银行的存款或者让 GFS 改变某个银行的存款。
该村子在财产上的求和运算等同于我们的乘法运算,也就是说领袖开户时的存款总和为(3^{100000})。这里发行的软妹面额是最小的(60)个素数((p_1=2,p_2=3,cdots,p_60=281)),任何人的财产都只能由这(60)个基本面额表示,即设某个人的财产为 (fortune)(正整数),则(fortune=p_1^{k_1}p_2^{k_2}cdots p_{60}^{K_{60}})

领袖习惯将一段编号连续的银行里的存款拿到一个账房去清点,为了避免 GFS 串通账房叛变,所以他不会每次都选择同一个账房。GFS 跟随领袖多年已经摸清了门路,知道领袖选择账房的方式。如果领袖选择清点编号在([a,b])内的银行财产,他会先对([a,b])的财产求和(计为(product)),然后在编号属于([1,product])的账房中选择一个去清点存款,检验自己计算是否正确同时也检验账房与 GFS 是否有勾结。
GFS 发现如果某个账房的编号(number)(product)相冲,领袖绝对不会选择这个账房。怎样才算与(product)不相冲呢?若存在整数(x,y)使得(numbercdot x+productcdot y=1),那么我们称(number)(product)不相冲,即该账房有可能被领袖相中。

当领袖又赚大钱了的时候,他会在某个银行改变存款,这样一来相同区间的银行在不同的时候算出来的(product)可能是不一样的,而且领袖不会在某个银行的存款总数超过(1000000)
现在GFS预先知道了领袖的清点存款与变动存款的计划,想请你告诉他,每次清点存款时领袖有多少个账房可以供他选择,当然这个值可能非常大,GFS只想知道对(19961993)取模后的答案。

Input

第一行一个整数(xle 10^5)表示领袖清点和变动存款的总次数。
接下来(x)行,每行(3)个整数(a_i,b_i,c_i)

  • (a_i)(0)时表示该条记录是清点计划,领袖会清点(b_i)(c_i)的银行存款,你需要对该条记录计算出 GFS 想要的答案。
  • (a_i)(1)时表示该条记录是存款变动,你要把银行(b_i)的存款改为(c_i),不需要对该记录进行计算。

Output

输出若干行,每行一个数,表示那些年的答案。

Sample Input

6
0 1 3
1 1 5
0 1 3
1 1 7
0 1 3
0 2 3

Sample Output

18
24
36
6

explanation

初始化每个国家存款都为(3);

(1)(3)(product)(27)([1,27])(27)不相冲的有(18)个数;
(1)的存款变为(5);
(1)(3)(product)(45)([1,45])(45)不相冲的有(24)个数;
(1)的存款变为(7);
(1)(3)(product)(63)([1,63])(63)不相冲的有(36)个数;
(2)(3)(product)(9)([1,9])(9)不相冲的有$64个数。


欧拉函数+线段树

题目里一堆废话,一开始看了样例解释才懂,所以也复制上来了
裴蜀定理告诉我们,题里那个存在整数(x,y)使得(numbercdot x+productcdot y=1)成立的条件,其实就是(gcd(number,product)=1)
又由于(numberle product),所以其实求的就是(varphi(product))
所以题目即为:求区间乘积的(varphi)函数取模,并支持单点修改


肯定是要用线段树,维护两个值,一个是区间乘积取模结果,一个是区间乘积有哪些质因数
由于题目告诉我们,不同质因数最多(60)个,所以我们用一个( exttt{long long})的第(i-1)个二进制位表示有没有第(i)小的质因数
然后合并信息的时候或一下就行,线段树压位常规套路

那么求(varphi)就用到这个公式

[varphi(n)=nprod frac{p_i-1}{p_i},p_iin prime,p_imid n ]

所以预处理一下逆元和质数就行了
记得左移的时候要写1ll

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<iomanip>
#include<cstring>
#define reg register
#define EN std::puts("")
#define LL long long
inline int read(){
	register int x=0;register int y=1;
	register char c=std::getchar();
	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
	return y?x:-x;
}
#define mod 19961993ll
int n;
struct tr{
	tr *ls,*rs;
	LL x,p;
}dizhi[200006],*root=&dizhi[0];
int tot;
int prime[305],notprime[305];
LL inv[305];
inline void pre(){
	inv[1]=1;
	for(reg int i=2;i<=300;i++){
		inv[i]=(mod-mod/i)*inv[mod%i]%mod;
		if(notprime[i]) continue;
		prime[++prime[0]]=i;
		for(reg int j=i+i;j<=300;j+=i) notprime[j]=1;
	}
}
void build(tr *tree,int l,int r){
	if(l==r) return tree->x=3,tree->p=2,void();
	int mid=(l+r)>>1;
	tree->ls=&dizhi[++tot];tree->rs=&dizhi[++tot];
	build(tree->ls,l,mid);build(tree->rs,mid+1,r);
	tree->x=tree->ls->x*tree->rs->x%mod;
	tree->p=tree->ls->p|tree->rs->p;
}
void change(tr *tree,int l,int r,int pos,int x){
	if(l==r){
		tree->x=x;
		tree->p=0;
		for(reg int i=1;i<=prime[0];i++)
			if(!(x%prime[i])) tree->p|=1ll<<(i-1);
		return;
	}
	int mid=(l+r)>>1;
	if(pos<=mid) change(tree->ls,l,mid,pos,x);
	else change(tree->rs,mid+1,r,pos,x);
	tree->x=tree->ls->x*tree->rs->x%mod;
	tree->p=tree->ls->p|tree->rs->p;
}
void qq(tr *tree,int l,int r,int ql,int qr,LL &x,LL &p){
	if(ql<=l&&r<=qr) return x=x*tree->x%mod,p|=tree->p,void();
	int mid=(l+r)>>1;
	if(ql<=mid) qq(tree->ls,l,mid,ql,qr,x,p);
	if(qr>mid) qq(tree->rs,mid+1,r,ql,qr,x,p);
}
int main(){
	n=read();
	reg int a,b,c;
	pre();build(root,1,100000);
	while(n--){
		a=read();b=read();c=read();
		if(a) change(root,1,100000,b,c);
		else{
			LL x=1,p=0;
			qq(root,1,100000,b,c,x,p);
//				std::printf("x=%lld  p=%lld
",x,p);
			for(reg int i=1;i<=prime[0];i++)
				if(p&(1ll<<(i-1))) x=(((x*(prime[i]-1))%mod)*inv[prime[i]])%mod;
			std::printf("%lld
",x);
		}
	}
//		for(reg int i=1;i<=300;i++) std::printf("%d : %lld
",i,inv[i]);
//		std::printf("prime[0]=%d",prime[0]);
	return 0;
}
原文地址:https://www.cnblogs.com/suxxsfe/p/12657215.html