题解——CodeForces 438D The Child and Sequence
题面
4 seconds
256 megabytes
standard input
standard output
At the children's day, the child came to Picks's house, and messed his house up. Picks was angry at him. A lot of important things were lost, in particular the favorite sequence of Picks.
Fortunately, Picks remembers how to repair the sequence. Initially he should create an integer array a[1], a[2], ..., a[n]. Then he should perform a sequence of m operations. An operation can be one of the following:
- Print operation l, r. Picks should write down the value of
. - Modulo operation l, r, x. Picks should perform assignment a[i] = a[i] mod x for each i (l ≤ i ≤ r).
- Set operation k, x. Picks should set the value of a[k] to x (in other words perform an assignment a[k] = x).
Can you help Picks to perform the whole sequence of operations?
The first line of input contains two integer: n, m (1 ≤ n, m ≤ 105). The second line contains n integers, separated by space: a[1], a[2], ..., a[n] (1 ≤ a[i] ≤ 109) — initial value of array elements.
Each of the next m lines begins with a number type
.
- If type = 1, there will be two integers more in the line: l, r (1 ≤ l ≤ r ≤ n), which correspond the operation 1.
- If type = 2, there will be three integers more in the line: l, r, x (1 ≤ l ≤ r ≤ n; 1 ≤ x ≤ 109), which correspond the operation 2.
- If type = 3, there will be two integers more in the line: k, x (1 ≤ k ≤ n; 1 ≤ x ≤ 109), which correspond the operation 3.
For each operation 1, please print a line containing the answer. Notice that the answer may exceed the 32-bit integer.
5 5
1 2 3 4 5
2 3 5 4
3 3 5
1 2 5
2 1 3 3
1 1 3
8
5
10 10
6 9 6 7 6 1 10 10 9 5
1 3 9
2 7 10 9
2 5 10 8
1 4 7
3 3 7
2 7 9 9
1 2 4
1 6 6
1 5 9
3 1 10
49
15
23
1
9
Consider the first testcase:
- At first, a = {1, 2, 3, 4, 5}.
- After operation 1, a = {1, 2, 3, 0, 1}.
- After operation 2, a = {1, 2, 5, 0, 1}.
- At operation 3, 2 + 5 + 0 + 1 = 8.
- After operation 4, a = {1, 2, 2, 0, 1}.
- At operation 5, 1 + 2 + 2 = 5.
简洁的题目翻译(取自luogu)
给定数列,区间查询和,区间取模,单点修改。
n,m小于10^5
题解
相当裸的一道线段树,但是思路相当神奇
首先我们会注意到,这题有要求区间修改和区间查询,学过线段树的神犇们可能就立刻会想到一系列诸如标记永久化,打lazytag等一系列高端操作来维护这颗线段树
但是实际上不用这样做哒qwq
否则你可能会像本蒟蒻一样在这道题上卡了一个半小时还一分都拿不到
因为这道题实际上是区间取模,取模实际上没办法像加法乘法一样做到利用一些lazytag的奇怪的做法把复杂度压成O(nlogn)
那么怎么做呢?
第四句话给了提示qwq
就是对要取模的区间暴力单点修改就行
这时候就有人要问了,这样暴力复杂度不对吧,当然不能,所以我们需要加一些玄学优化
首先我们要证明一些奇怪的东西
引理1:对一个数取模,如果能够取模,那么这个数至少会变成原来的\( \frac{1}{2} \),这非常的显然,所以我就懒得证明了23333
还是简单的证明一下,如果一个数能够被取模,则取模后它一定会变成小于模数的形式,如果模数大于原数的\( \frac {1}{2} \)则取模后结果一定会小于原数减去模数即结果一定小于原数的\( \frac {1}{2} \) ,现在考虑另一种情况,若模数小于原数的\( \frac {1}{2} \),则取模后的结果一定会小于模数,即结果一定小于等于原数的\( \frac {1}{2} \)
所以现在得证,一个数取模后规模至少缩小\( \frac{1}{2} \)
然后我们继续证明一些性质
引理2:若一个数被取模,则至多取模\( \lg N \)次
由引理1可知,一个数每次被取模规模都会缩小\( \frac{1}{2}\),所以只需要取模\( \lg N \)次就不可以继续取模了
现在有了这两个性质,我们再进行一些合理的猜想
取模运算很慢,那么为了减少运行时间,我们在能够不取模的时候应当不取模
引理3:若一个数小于模数,那么这个数取模后的结果和原数相等
显然,根据模除的性质,若这个数小于模数,那么除法运算最后的余数一定与原数相等
既然可能相等,我们就在出现相等情况时不取模就好了
因此,我们再在区间和之外多维护一个区间最大值即可,当模数大于区间最大值时,不对这个区间进行取模操作
下面就可以进行复杂度证明了
复杂度:O(nlogn)
证明:总共有n个数,因为一旦取模后结果可能不变就不会继续取模,所以每个数最多被取模\( \lg N \)次,所以最终的取模次数最多为nlogn次,时间复杂度为O(nlogn)
证毕
单点修改没什么好说的,现在我们就可以任性的取模了
贴代码
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXN = ;
long long maxm[MAXN<<],sum[MAXN<<],a[MAXN];
long long n,m;
void pushup(long long o){
maxm[o]=max(maxm[o<<],maxm[o<<|]);
sum[o]=(sum[o<<]+sum[o<<|]);
}
void build(long long l,long long r,long long o){
if(l==r){
sum[o]=a[l];
maxm[o]=a[l];
return;
}
long long mid=(l+r)>>;
build(l,mid,o<<);
build(mid+,r,o<<|);
pushup(o);
}
void updateadd(long long pos,long long l,long long r,long long o,long long v){
if(l==r){
sum[o]=v;
maxm[o]=v;
return;
}
long long mid=(l+r)>>;
if(pos<=mid)
updateadd(pos,l,mid,o<<,v);
else
updateadd(pos,mid+,r,o<<|,v);
pushup(o);
}
void updatemod(long long pos,long long l,long long r,long long o,long long v){
if(l==r){
sum[o]=sum[o]%v;
maxm[o]=maxm[o]%v;
}
long long mid=(l+r)>>;
if(pos<=mid)
updatemod(pos,l,mid,o<<,v);
else
updatemod(pos,mid+,r,o<<|,v);
pushup(o);
}
long long query(long long L,long long R,long long l,long long r,long long o){
if(L<=l&&r<=R){
return sum[o];
}
long long ans=,mid=(l+r)>>;
if(L<=mid)
ans+=query(L,R,l,mid,o<<);
if(R>mid)
ans+=query(L,R,mid+,r,o<<|);
return ans;
}
void update(long long L,long long R,long long l,long long r,long long o,long long v){
if(l==r){
sum[o]=sum[o]%v;
maxm[o]=maxm[o]%v;
return;
}
long long mid=(l+r)>>;
if(L<=mid&&maxm[o<<]>=v)
update(L,R,l,mid,o<<,v);
if(R>mid&&maxm[o<<|]>=v)
update(L,R,mid+,r,o<<|,v);
pushup(o);
}
int main(){
scanf("%lld %lld",&n,&m);
for(int i=;i<=n;i++)
scanf("%d",&a[i]);
build(,n,);
for(int i=;i<=m;i++){
int mode;
scanf("%d",&mode);
if(mode==){
long long lx,rx;
scanf("%lld %lld",&lx,&rx);
printf("%lld\n",query(lx,rx,,n,));
}
else if(mode==){
long long lx,rx,x;
scanf("%lld %lld %lld",&lx,&rx,&x);
update(lx,rx,,n,,x);
}
else{
long long k,x;
scanf("%lld %lld",&k,&x);
updateadd(k,,n,,x);
}
}
return ;
}
题解——CodeForces 438D The Child and Sequence的更多相关文章
- Codeforces 438D The Child and Sequence - 线段树
At the children's day, the child came to Picks's house, and messed his house up. Picks was angry at ...
- Codeforces 438D The Child and Sequence
题意:给定一个n个数的序列,完成以下3个操作: 1.给定区间求和 2.给定区间对x取模 3.单点修改 对一个数取模,这个数至少折半.于是我们记一个最大值max,如果x>max则不做处理. #in ...
- 2018.07.23 codeforces 438D. The Child and Sequence(线段树)
传送门 线段树维护区间取模,单点修改,区间求和. 这题老套路了,对一个数来说,每次取模至少让它减少一半,这样每次单点修改对时间复杂度的贡献就是一个log" role="presen ...
- CodeForces 438D The Child and Sequence (线段树 暴力)
传送门 题目大意: 给你一个序列,要求在序列上维护三个操作: 1)区间求和 2)区间取模 3)单点修改 这里的操作二很讨厌,取模必须模到叶子节点上,否则跑出来肯定是错的.没有操作二就是线段树水题了. ...
- 438D - The Child and Sequence
D. The Child and Sequence time limit per test 4 seconds memory limit per test 256 megabytes input st ...
- CF(438D) The Child and Sequence(线段树)
题意:对数列有三种操作: Print operation l, r. Picks should write down the value of . Modulo operation l, r, x. ...
- Codeforces 438D (今日gg模拟第二题) | 线段树 考察时间复杂度的计算 -_-|||
Codeforces 438D The Child and Sequence 给出一个序列,进行如下三种操作: 区间求和 区间每个数模x 单点修改 如果没有第二个操作的话,就是一棵简单的线段树.那么如 ...
- Codeforces Round #250 (Div. 1) D. The Child and Sequence 线段树 区间取摸
D. The Child and Sequence Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest ...
- Codeforces Round #250 (Div. 1) D. The Child and Sequence 线段树 区间求和+点修改+区间取模
D. The Child and Sequence At the children's day, the child came to Picks's house, and messed his h ...
随机推荐
- html5-边框属性
width: 500px; height: 300px; background: rgb(122,30,60); border: 10px solid black; /*bor ...
- Java多线程-----匿名内部类创建线程
1.继承Thread类创建线程 package com.practise.createthread; public class AnonymousThread { public static v ...
- session_start 统计实时访客人数
void Session_Start(object sender, EventArgs e) { Application.Lock(); Application["OnLine"] ...
- QString 与 string转换
[1]QString 转换为string QString qString("好好学习天天向上"); std::string stdString = qString.toStdStr ...
- QPushButton 控制两种状态
[1]Custom.cpp #include "CustomButton.h" CustomButton::CustomButton(QWidget* parent) : QPus ...
- STL容器之list
[1]list简介 实质上,list容器就是一个双向链表,可以高效地进行插入.删除操作. [2]list链表常用方法 (1)构造.赋值.清空.删除.插入.判空等 应用示例代码如下: #include ...
- python 将字节写入文本文件
想在文本模式打开的文件中写入原始的字节数据 将字节数据直接写入文件的缓冲区即可 >>> import sys >>> sys.stdout.write(b'Hell ...
- 转:获得数据库自增长ID(ACCESS)与(SQLSERVER)
转载自:http://www.cnblogs.com/chinahnzl/articles/968649.html 问题CSDN 里面不时有初学者疑惑:如何获取自增长列(标识列)的ID,并写入另一张表 ...
- sql之left join、right join、inner join的区别,连接自己时的查询结果测试
sql之left join.right join.inner join的区别 left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录 right join(右联接) 返回包括 ...
- Java中在java.sql.Date的系统时间上加上30天并写入oracle
在java.sql.Date的系统时间上加上30天,并写入oracle 思路:通过 Calendar.getInstance() 获得对象,然后 add() 方法添加 时间,再通过 new java. ...