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)就用到这个公式
所以预处理一下逆元和质数就行了
记得左移的时候要写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;
}