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\n",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

posted @ 2018-10-13 20:52  露迭月  阅读(390)  评论(0编辑  收藏  举报