一道很好的线段树+求欧拉函数题!!!
先简单理解一下题意:给你一段长度为n的区间,q次操作,输入为1时将l~r区间每个数乘上x,输入为2时求解\(\varphi(\prod_{i=l} ^{r} {a_i})\) 。
赛时心历经过:
第一眼感觉是个线段树板子题,赛时也是这么想的,打到一半发现不对劲,首先这个乘积就没法维护,随便乘两下就炸了,再其次这么大的数我也不会求\(\varphi\)值呀但打都打了就只能硬着头皮打下去,厉害的是我一个线段树一遍就打过了(当然仅限于小样例),抱着侥幸心理交了,不出所料的爆零了。
赛后去查了一下怎么能利用\(\varphi\)的性质优化一下然后就发现了这么一个已经被我遗忘的东西
\[\varphi(n)=n\times \prod_{i=1}^{k}{(1- \frac{1}{p_i})} \]其中\(p_1,p_2...p_n\)为n的所有质因数,n为正整数
这样搞的话就可以边\(mod\)边乘了!
用线段树维护两个东西一个是\(a[i]\)的乘积,一个是后面那一坨连乘,\(a[i]\)的乘积很好维护,但就是后面那一坨,(⊙o⊙)…难以描述,只好集思广益一下,得出结果:
把\(1-300\)里的质数预处理出来,发现只有62个,嘿嘿嘿(一脸坏笑),long long 好像可以存63位是吧,那就不好意思了,直接就是状压一下最后统计这个区间里的所有质因数。
问题迎刃而解!!!
最后附上代码::
#include<bits/stdc++.h>
#define int long long
#define ls rt<<1
#define rs rt<<1|1
using namespace std;
const int N=4e5+5,p=1e9+7;
int n,m,t;
int z,x,y,tot,a[N];
int phi[N],prime[N];
string op;
struct sb{
int l,r,x,lazy1,lazy2=1,size,phi;
}tr[N<<2];
int qp(int a,int n){
int ans=1;
while(n){
if(n&1)ans=ans*a%p;
a=a*a%p;
n>>=1;
}
return ans;
}
int ny(int x){
return qp(x,p-2);
}
void iint(){
for(int i=2;i<=300;i++){
bool vis=0;
for(int j=2;j<=sqrt(i);j++){
if(i%j==0)vis=1;
}if(vis==0)prime[++tot]=i,phi[tot]=(i-1)*ny(i)%p;
}
}
void pushup(int rt){
tr[rt].x=tr[ls].x*tr[rs].x%p;
tr[rt].size=tr[ls].size+tr[rs].size;
tr[rt].phi=(tr[ls].phi|tr[rs].phi);
}
void pushdown(int rt){
int l1=tr[rt].lazy1;
if(l1){
tr[ls].phi=(tr[ls].phi|l1);
tr[rs].phi=(tr[rs].phi|l1);
tr[ls].lazy1|=l1;
tr[rs].lazy1|=l1;
tr[rt].lazy1=0;
}
int l2=tr[rt].lazy2;
if(l2!=1){
tr[ls].x=tr[ls].x*qp(l2,tr[ls].size)%p;
tr[rs].x=tr[rs].x*qp(l2,tr[rs].size)%p;
tr[ls].lazy2=tr[ls].lazy2*l2%p;
tr[rs].lazy2=tr[rs].lazy2*l2%p;
tr[rt].lazy2=1;
}
}
void build(int rt,int l,int r){
tr[rt].l=l;
tr[rt].r=r;
if(l==r){
tr[rt].x=a[l];
tr[rt].size=1;
for(int i=1;i<=tot;i++){
if(a[l]%prime[i]==0){
tr[rt].phi=(tr[rt].phi|(1ll<<i));
}
}
return;
}
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
pushup(rt);
}
void change(int rt,int l,int r,int x){
if(tr[rt].l>=l&&tr[rt].r<=r){
int sum=0;
for(int i=1;i<=tot;i++){
if(x%prime[i]==0){
sum=(sum|(1ll<<i));
}
}
tr[rt].x=tr[rt].x*qp(x,tr[rt].size)%p;
tr[rt].phi|=sum;
tr[rt].lazy1|=sum;
tr[rt].lazy2=tr[rt].lazy2*x%p;
return;
}
pushdown(rt);
int mid=(tr[rt].l+tr[rt].r)>>1;
if(l<=mid)change(ls,l,r,x);
if(r>mid)change(rs,l,r,x);
pushup(rt);
}
int query(int rt,int l,int r){
pushdown(rt);
if(tr[rt].l>=l&&tr[rt].r<=r)return tr[rt].x;
int mid=(tr[rt].l+tr[rt].r)>>1;
int ans=1;
if(l<=mid)ans=ans*query(ls,l,r)%p;
if(r>mid)ans=ans*query(rs,l,r)%p;
return ans%p;
}
int Query(int rt,int l,int r){
pushdown(rt);
if(tr[rt].l>=l&&tr[rt].r<=r){
return tr[rt].phi;
}
int mid=(tr[rt].l+tr[rt].r)>>1;
int ans=0;
if(l<=mid)ans=(ans|Query(ls,l,r));
if(r>mid)ans=(ans|Query(rs,l,r));
return ans;
}
signed main(){
// freopen("array.in","r",stdin);
// freopen("array.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
iint();
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
build(1,1,n);
while(m--){
cin>>op>>x>>y;
if(op[0]=='1'){
cin>>z;
change(1,x,y,z);
}
else{
int k=Query(1,x,y);
int sum=1;
for(int i=1;i<=62;i++){
if((k>>i)&1)sum=sum*phi[i]%p;
}
int aaa=query(1,x,y);
cout<<aaa*sum%p<<endl;
}
}
return 0;
}
完结撒花!!!
标签:rt,return,rs,int,tr,CF1114F,Please,ans,Array From: https://www.cnblogs.com/houburzyx/p/18299327