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\)

转载于:https://www.cnblogs.com/Yuhuger/p/10367171.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值