[线段树 区间取模] D. The Child and Sequence
Posted 鱼竿钓鱼干
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[线段树 区间取模] D. The Child and Sequence相关的知识,希望对你有一定的参考价值。
[线段树 区间取模] D. The Child and Sequence
题目
思路
区间求和,单点修改,区间取模
区间取和和单点修改比较easy
主要问题是区间取模怎么做,其实和区间开根类似
我们没法对整段区间中每个数字取模后没法立刻得到sum,所以没法直接使用lazy标记
但是我们可以发现,区间取模操作一定次数后有很大概率<mod,不需要操作(具体证明可以看其他博客),因此我们可以通过剪枝优化,维护一个区间最大值,如果区间最大值<mod,那么可以直接跳过这个区间的修改操作,否则直接单点暴力修改即可。
所以也不需要什么lazy标记来区间修改了。
代码
单点修改的时候别忘了修改最大值啊啊啊!
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+10;
typedef long long LL;
struct tnode{
int l,r;
LL sum,mx;
};
struct Segment_Tree{
tnode t[MAXN<<2];
int leaf[MAXN];
void update(int root){
int ch=root<<1;
t[root].sum=t[ch].sum+t[ch+1].sum;
t[root].mx=max(t[ch].mx,t[ch+1].mx);
}
void build(int root,int l,int r,int *A){
t[root].l=l;t[root].r=r;
if(l!=r){
int mid=(l+r)>>1;
int ch=root<<1;
build(ch,l,mid,A);
build(ch+1,mid+1,r,A);
update(root);
}
else{
t[root].sum=A[l];
t[root].mx=A[l];
leaf[l]=root;
}
}
void change(int root,LL x){
root=leaf[root];
t[root].sum=t[root].mx=x;
while(root/=2) update(root);
}
void get_mod(int root,int l,int r,LL mod){
int mid=(t[root].l+t[root].r)>>1;
int ch=root<<1;
if(t[root].l==l&&t[root].r==r){
if(t[root].mx<mod)return;
if(l==r){
t[root].sum%=mod;
t[root].mx=t[root].sum;
return;
}
get_mod(ch,l,mid,mod);
get_mod(ch+1,mid+1,r,mod);
update(root);
return;
}
if(r<=mid) get_mod(ch,l,r,mod);
else if(l>mid) get_mod(ch+1,l,r,mod);
else{
get_mod(ch,l,mid,mod);
get_mod(ch+1,mid+1,r,mod);
}
update(root);
}
LL sum(int root,int l,int r){
int mid=(t[root].l+t[root].r)>>1;
int ch=root<<1;
if(t[root].l==l&&t[root].r==r){
return t[root].sum;
}
if(r<=mid)return sum(ch,l,r);
else if(l>mid)return sum(ch+1,l,r);
else{
return sum(ch,l,mid)+sum(ch+1,mid+1,r);
}
}
};
Segment_Tree ST;
int n,m,k,op;
LL x;
int a[MAXN];
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
ST.build(1,1,n,a);
for(int i=1;i<=m;i++){
int l,r;
scanf("%d",&op);
if(op==1){
scanf("%d%d",&l,&r);
printf("%lld\\n",ST.sum(1,l,r));
}
else if(op==2){
scanf("%d%d%lld",&l,&r,&x);
ST.get_mod(1,l,r,x);
}
else{
scanf("%d%lld",&k,&x);
ST.change(k,x);
}
}
return 0;
}
以上是关于[线段树 区间取模] D. The Child and Sequence的主要内容,如果未能解决你的问题,请参考以下文章
CodeForces 438D. The Child and Sequence(线段树区间更新)
CF438D The Child and Sequence 线段树
CF438DThe Child and Sequence(线段树)
codeforces438D The Child and Sequence