BZOJ(本校) 3046 简单数学问题 - 线段树

时限:1s 内存:64MB
题目描述
首先给你一个包含个整数的数列,你需要处理以下两种操作:
1.对区间内的每个数,乘上或者除以一个整数
2.输出区间内每个数的乘积对某个特定模数取模的值

输入格式
输入文件的第一行有两个整数和
第二行包含个整数,表示起始的的值
第三行包含一个整数,表示操作的次数。接下来的行,每行表示一次操作。
对于操作”M L R x”,表示对于区间内的每个数,将它的值乘上
对于操作”D L R x”,表示对于区间内的每个数,将它的值除以
数据保证区间内的每个数都能被整除。
对于操作”“Q L R”,表示询问区间内所有数的乘积对取模的值。
数据保证每次操作中的小于等于。

输出格式
对于每次询问”Q L R”,输出一行表示要求的结果。

样例输入
5 6
10 2 6 9 10
5
Q 1 2
M 1 4 3
Q 1 5
D 1 3 2
Q 1 3

样例输出
2
0
3

分析:

用线段树搞很显然。
但是del的时候会出现del的数和Mod不互质,无法求逆元的情况。
solution:看代码吧,深感表述之累。

代码写wa了,调不出来了,心累死了,无奈抄代码呀。

#include<cstdio>
#include<cmath>
#define MAXN 10000
#define MAXKD 10

struct node{
    int tag,sum;
}tre[MAXKD+10][MAXN*4+10];

int n,Mod,fac[MAXN+10],cntf;

void Build(node *tre,int u,int l,int r)
{
    tre[u].sum=1%Mod;
    tre[u].tag=1%Mod;
    if(l==r) return ;
    int mid=(l+r)>>1;
    Build(tre,u<<1,l,mid),Build(tre,(u<<1)|1,mid+1,r);
}
void Getfac(int M)
{
    int side=sqrt(M+0.5);
    for(int i=2;i<=side;i++)
        if(M%i==0){
            fac[++cntf]=i;
            while(M%i==0)
                M/=i;
        }
    if(M>1)
        fac[++cntf]=M;
}
int mypow(int x,long long k)
{
    int ret=1;
    while(k){
        if(k&1)
            ret=1LL*ret*x%Mod;
        x=1LL*x*x%Mod;
        k>>=1;
    }
    return ret;
}
void Push_down(node *tre,int u,int l,int r)
{
    if(!tre[u].tag) return ;
    tre[u<<1].tag+=tre[u].tag;
    tre[(u<<1)|1].tag+=tre[u].tag;
    int mid=(l+r)>>1;
    tre[u<<1].sum+=tre[u].tag*(mid-l+1);
    tre[(u<<1)|1].sum+=tre[u].tag*(r-mid);
    tre[u].tag=0;
}
void Insert(node *tre,int u,int l,int r,int L,int R,int d)
{
    if(r<L||l>R) return ;
    if(L<=l&&r<=R){
        tre[u].tag+=d;
        tre[u].sum+=(r-l+1)*d;
        return ;
    }
    Push_down(tre,u,l,r);
    int mid=(l+r)>>1;
    Insert(tre,u<<1,l,mid,L,R,d);
    Insert(tre,(u<<1)|1,mid+1,r,L,R,d);
    tre[u].sum=tre[u<<1].sum+tre[(u<<1)|1].sum;
}
void Push_down_re(node *tre,int u,int l,int r)
{
    if(tre[u].tag==1) return ;
    tre[u<<1].tag=1LL*tre[u<<1].tag*tre[u].tag%Mod;
    tre[(u<<1)|1].tag=1LL*tre[(u<<1)|1].tag*tre[u].tag%Mod;
    int mid=(l+r)>>1;
    tre[u<<1].sum=1LL*tre[u<<1].sum*mypow(tre[u].tag,mid-l+1)%Mod;
    tre[(u<<1)|1].sum=1LL*tre[(u<<1)|1].sum*mypow(tre[u].tag,r-mid)%Mod;
    tre[u].tag=1;
}
void Insert_re(node *tre,int u,int l,int r,int L,int R,int d)
{
    if(l>R||r<L) return ;
    if(L<=l&&r<=R){
        tre[u].tag=1LL*tre[u].tag*d%Mod;
        tre[u].sum=1LL*tre[u].sum*mypow(d,r-l+1)%Mod;
        return ;
    }
    Push_down_re(tre,u,l,r);
    int mid=(l+r)>>1;
    Insert_re(tre,u<<1,l,mid,L,R,d);
    Insert_re(tre,(u<<1)|1,mid+1,r,L,R,d);
    tre[u].sum=1LL*tre[u<<1].sum*tre[(u<<1)|1].sum%Mod;
}
void read()
{
    int x;
    scanf("%d%d",&n,&Mod);
    Build(tre[0],1,1,n);
    Getfac(Mod);
    for(int i=1;i<=n;i++){
        scanf("%d",&x);
        if(!x){
            Insert_re(tre[0],1,1,n,i,i,x);
            continue;
        }
        for(int j=1,cnt;j<=cntf;j++)
            if(x%fac[j]==0){
                cnt=0;
                while(x%fac[j]==0)
                    x/=fac[j],cnt++;
                Insert(tre[j],1,1,n,i,i,cnt);
            }
        Insert_re(tre[0],1,1,n,i,i,x);
    }
}
void Mul(int L,int R,int x)
{
    if(!x){
        Insert_re(tre[0],1,1,n,L,R,x);
        return ;
    }
    for(int j=1,cnt;j<=cntf;j++)
        if(x%fac[j]==0){
            cnt=0;
            while(x%fac[j]==0)
                x/=fac[j],cnt++;
            Insert(tre[j],1,1,n,L,R,cnt);
        }
    Insert_re(tre[0],1,1,n,L,R,x);
}
void exgcd(int a,int b,int &d,int &x,int &y)
{
    if(!b){
        d=a;
        x=1,y=0;
        return ;
    }
    exgcd(b,a%b,d,y,x);
    y-=(a/b)*x;
}
void Del(int L,int R,int x)
{
    for(int j=1,cnt;j<=cntf;j++)
        if(x%fac[j]==0){
            cnt=0;
            while(x%fac[j]==0)
                x/=fac[j],cnt++;
            Insert(tre[j],1,1,n,L,R,-cnt);
        }
    int d,a,b;
    exgcd(x,Mod,d,a,b);
    a=(1LL*a%Mod+Mod)%Mod;
    Insert_re(tre[0],1,1,n,L,R,a);
}
int Getsum_re(node *tre,int u,int l,int r,int L,int R)
{
    if(r<L||R<l) return 1;
    if(L<=l&&r<=R)
        return tre[u].sum;
    Push_down_re(tre,u,l,r);
    int mid=(l+r)>>1;
    return 1LL*Getsum_re(tre,u<<1,l,mid,L,R)*Getsum_re(tre,(u<<1)|1,mid+1,r,L,R)%Mod;
}
long long Getsum(node *tre,int u,int l,int r,int L,int R)
{
    if(r<L||R<l) return 0;
    if(L<=l&&r<=R)
        return tre[u].sum;
    Push_down(tre,u,l,r);
    int mid=(l+r)>>1;
    return 1LL*Getsum(tre,u<<1,l,mid,L,R)+Getsum(tre,(u<<1)|1,mid+1,r,L,R);
}
int Quary(int L,int R)
{
    int ret=Getsum_re(tre[0],1,1,n,L,R);
    if(!ret)
        return 0;
    for(int i=1;i<=cntf;i++)
        ret=1LL*ret*mypow(fac[i],Getsum(tre[i],1,1,n,L,R))%Mod;
    return ret;
}
void workout()
{
    int Q,L,R,x;
    char s[20];
    scanf("%d",&Q);
    while(Q--){
        scanf("%s",s);
        if(s[0]=='M'){
            scanf("%d%d%d",&L,&R,&x);
            Mul(L,R,x);
        }
        else if(s[0]=='D'){
            scanf("%d%d%d",&L,&R,&x);
            Del(L,R,x);
        }
        else{
            scanf("%d%d",&L,&R);
            printf("%d\n",Quary(L,R));
        }
    }
}
int main()
{
    read();
    workout();
    return 0;
} //powered by Liu junhao's
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值