CF1114F Please, another Queries on Array?

一道很好的线段树+求欧拉函数题!!!
先简单理解一下题意:给你一段长度为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;
}

完结撒花!!!

posted @ 2024-07-12 20:22  houbur  阅读(26)  评论(0编辑  收藏  举报