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