codeforces 1114F

虽然挺好想,但是很难写。
还是第一次写带标记永久化的区间操作,区间查询线段树。
修改时一直根据实际长度改值,被包含时改标记。
查询时被包含算值,否则一直根据实际长度算标记。

#include <bits/stdc++.h>
using namespace std;
const int M=1e9+7;
const int C=62;
typedef long long lll;
const int N=400010;
int a[N];
struct node{
    int val,tag;
    lll app,pag;
}T[1<<20];
int p[C],inv[C];
lll rep(int x){
    lll ret=0;
    for (int i=0; i<C; ++i) if (x%p[i]==0) ret|=1ll<<i;
    return ret;
}
bool b[400];
int fp(int x,int y){
    int ret=1;
    for (; y; y>>=1,x=(lll)x*x%M) if (y&1) ret=(lll)ret*x%M;
    return ret;
}
int ll,rr,cc,n,q;
lll cf;
void build(int ind,int l,int r){
    T[ind].tag=1;
    if (l==r){
	T[ind].val=a[l];
	T[ind].app=rep(a[l]);
	return;
    }
    int mid=(l+r)>>1;
    build(ind<<1,l,mid);
    build(ind<<1|1,mid+1,r);
    T[ind].app=T[ind<<1].app|T[ind<<1|1].app;
    T[ind].val=(lll)T[ind<<1].val*T[ind<<1|1].val%M;
}
void update(int ind,int l,int r){
    T[ind].app|=cf;
    lll d=fp(cc,min(r,rr)-max(l,ll)+1);
    T[ind].val=T[ind].val*d%M;
    if (ll<=l&&r<=rr){
	//cerr<<"CD"<<cc<<" "<<l<<" "<<r<<endl;
	T[ind].tag=(lll)T[ind].tag*cc%M;
	T[ind].pag|=cf;
	return;
    }
    int mid=(l+r)>>1;
    if (ll<=mid) update(ind<<1,l,mid);
    if (mid<rr) update(ind<<1|1,mid+1,r);
}
void ask(int ind,int l,int r){
    if (ll<=l&&r<=rr){
	//cerr<<l<<" "<<r<<" "<<T[ind].val<<endl;
	cc=(lll)T[ind].val*cc%M;
	cf|=T[ind].app;
	return;
    }
    cc=(lll)fp(T[ind].tag,(min(r,rr)-max(l,ll)+1))*cc%M;
    cf|=T[ind].pag;
    int mid=(l+r)>>1;
    if (ll<=mid) ask(ind<<1,l,mid);
    if (mid<rr) ask(ind<<1|1,mid+1,r);
}
int main(){
    int pnum=0;
    for (int i=2; i<=300; ++i){
	if (b[i]) continue;
	p[pnum++]=i;
	for (int j=i*i; j<=300; j+=i)
	    b[j]=1;
    }
    for (int i=0; i<pnum; ++i) inv[i]=fp(p[i],M-2);
    scanf("%d%d",&n,&q);
    for (int i=1; i<=n; ++i){
	scanf("%d",&a[i]);
    }
    build(1,1,n);
    for (int i=1; i<=q; ++i){
	char s[10];
	scanf("%s%d%d",s,&ll,&rr);
	if (s[0]=='T'){
	    cc=1; cf=0;
	    ask(1,1,n);
	    //cerr<<"CC"<<cc<<endl;
	    for (int i=0; i<C; ++i) if ((cf>>i)&1) cc=(lll)cc*inv[i]%M*(p[i]-1)%M;
	    cout<<cc<<'\n';
	}
	else{
	    scanf("%d",&cc);
	    cf=rep(cc);
	    update(1,1,n);
	}
    }
}

快速幂预处理分类讨论一下,应该也可一个\(log\)

posted @ 2019-02-12 21:30  Yuhuger  阅读(235)  评论(0编辑  收藏  举报