mod

mod

题目描述

给定一个长度为 (n) 的非负整数序列 (a),你需要支持以下操作:
1:给定 (l,r),输出 (a[l]+a[l+1]+…+a[r])
2:给定 (l,r,x),将 (a[l],a[l+1],…,a[r])(x) 取模。
3:给定 (k,y),将 (a[k])修改为 (y)

输入数据

第一行两个整数 (n),(m)

第二行 (n) 个整数 (a[1]~a[n])。接下来 (m) 行每行 (3)(4) 个整数表示操作。

输出数据

对于每个操作 (1),输出一行一个整数表示答案。

数据范围

对于 (40\%) 的数据, (n,m<=1000)
对于 (100\%) 的数据,(n,m<=100000)(1<=l<=r<=n)(1<=k<=n)(1<=x<=10^9)
(0<=a[i],y<=10^9)


最开始只想着乱搞,结果过了,然后发现就是正解。。

维护区间和和区间max,每次暴力取模,如果(max)比模数小,就不进那个区间。

复杂度是(O(nlog^2n))

为什么呢?本着**的精神,我去研究了一下势能分析,看懂了是看懂了,但我并不会用来分析这个题。

简单说一下我的理解吧。

注意到每次取模最少把一个数缩小一半

所以在没有修改时总取模次数小于(nlognlog1e9)

一次单点修改至多使时间复杂度增加(lognlog1e9)


Code:

#include <cstdio>
#define ls id<<1
#define rs id<<1|1
#define ll long long
const int N=1e5+10;
int n,m,a[N];
ll mx[N<<2],sum[N<<2];
ll max(ll x,ll y){return x>y?x:y;}
void updata(int id)
{
    sum[id]=sum[ls]+sum[rs];
    mx[id]=max(mx[ls],mx[rs]);
}
void change(int id,int L,int R,int l,int r,ll x)
{
    if(mx[id]<x) return;
    if(L==R){sum[id]%=x;mx[id]%=x;return;}
    int Mid=L+R>>1;
    if(r<=Mid) change(ls,L,Mid,l,r,x);
    else if(l>Mid) change(rs,Mid+1,R,l,r,x);
    else change(ls,L,Mid,l,Mid,x),change(rs,Mid+1,R,Mid+1,r,x);
    updata(id);
}
void change0(int id,int l,int r,int pos,ll x)
{
    if(l==r) {sum[id]=mx[id]=x;return;}
    int mid=l+r>>1;
    if(pos<=mid) change0(ls,l,mid,pos,x);
    else change0(rs,mid+1,r,pos,x);
    updata(id);
}
ll query(int id,int L,int R,int l,int r)
{
    if(l==L&&r==R) return sum[id];
    int Mid=L+R>>1;
    if(r<=Mid) return query(ls,L,Mid,l,r);
    else if(l>Mid) return query(rs,Mid+1,R,l,r);
    else return query(ls,L,Mid,l,Mid)+query(rs,Mid+1,R,Mid+1,r);
}
void build(int id,int l,int r)
{
    if(l==r)
    {
        mx[id]=sum[id]=1ll*a[l];
        return;
    }
    int mid=l+r>>1;
    build(ls,l,mid),build(rs,mid+1,r);
    updata(id);
}
int read()
{
    int x=0;char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
    return x;
}
int main()
{
    //freopen("data.in","r",stdin);
    //freopen("lg.out","w",stdout);
    n=read(),m=read();
    for(int i=1;i<=n;i++) a[i]=read();
    build(1,1,n);
    for(int op,l,r,x,i=1;i<=m;i++)
    {
        op=read();
        if(op==1)
        {
            l=read(),r=read();
            printf("%lld
",query(1,1,n,l,r));
        }
        else if(op==2)
        {
            l=read(),r=read(),x=read();
            change(1,1,n,l,r,1ll*x);
        }
        else
        {
            l=read(),x=read();
            change0(1,1,n,l,1ll*x);
        }
    }
    return 0;
}

2018.10.13

原文地址:https://www.cnblogs.com/butterflydew/p/9784113.html