The Child and Sequence(线段树取模/区间最大值)

The Child and Sequence

传送门 Problem - 438D - Codeforces

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:

  1. Print operation l, r. Picks should write down the value of img.
  2. Modulo operation l, r, x. Picks should perform assignment a[i] = a[i] mod x for each i (l ≤ i ≤ r).
  3. 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?

Input

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 img.

  • 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.

Output

For each operation 1, please print a line containing the answer. Notice that the answer may exceed the 32-bit integer.

题意

给定序列,完成三项操作:求出序列和,对某一序列的元素a[i]=a[i] mod x,修改单点值。

思路

设reminder为a[i]%x,那么a[i]=k*x+reminder.当k=0时,不用做计算;当k!=0时,要做计算,对单点值修改。每次修改后a[i]变为不到原来的一半。

最重要的是减少修改和递归次数。维护区间最大值mx,方便查看此区间是否有修改的必要从而减少修改次数。

受到之前一题的影响(就是区间开根号的一道题),那一题是看区间大小是否等于区间和来判断是否有必要继续对区间开根。我这题也鲨臂的用了这一判断准则,只是改成了小于等于,结果WA。维护最大值我甚至还写了个query_maxV函数,结果TLE了,后来发现写在update里面,用就行了…还有就是modify在le<=s && t<=ri的时候老忘记更新犯错。然后写lson和rson会更方便,不容易写错。

#include <bits/stdc++.h>
typedef long double ld;
typedef long long ll;
#define pb push_back
#define mk make_pair
#define mt make_tuple
#define eb emplace_back
#define pob pop_back
#define rz resize
#define all(a) (a).begin(),(a).end()
#define rall(a) (a).rbegin(),(a).rend()
#define debug(a) cout<<#a<<"="<<a<<endl;
#define qwe(i,a,b) for(int i=a;i<=b;i++)
#define ewq(i,a,b) for(int i=a;i>=b;i--)
inline ll rr(){ll f=1,x=0;char ch;do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');return f*x;}
using namespace std;
const int maxn=1e5+6;

int n,m;
#define lson s,mid,p<<1
#define rson mid+1,t,p<<1|1
struct node {
    ll v,c,sz,mx; // 区间总和 区间修改为某一定值的tag 区间大小 区间最大值
    // 后来发现是单点修改,所以这个c没用了,下面的settag,pushdown也没用了
}se[maxn<<2];
ll a[maxn];
inline void update(int p) {
    se[p].v=se[p<<1].v+se[p<<1|1].v;
    se[p].mx=max(se[p<<1].mx,se[p<<1|1].mx);
}
inline void settag(int p,ll t) {
    if(se[p].c) {
        se[p].c=t; // 压标记
        // 更新当前区间特征
        se[p].v=se[p].sz*t;
    }
}
inline void pushdown(int p) {
    // 标记下传
    settag(p<<1,se[p].c);
    settag(p<<1|1,se[p].c);
    // 刷新父标记
    se[p].c=0;
}
void build(int s,int t,int p) {
    if(s == t) {se[p]={a[s],0,t-s+1,a[s]};return ;}
    int mid=(s+t)>>1;
    build(lson),build(rson);
    update(p);
}
void modify_mod(int le,int ri,int k,int s,int t,int p) {
    // if(le<=s && t<=ri) if(query_maxV(le,ri,s,t,p)<k) return ;
    if(se[p].mx<k) return ;
    if(s == t) {se[p].v=se[p].mx=se[p].v%k;return ;}
    int mid=(s+t)>>1;
    if(le<=mid) modify_mod(le,ri,k,lson);
    if(ri >mid) modify_mod(le,ri,k,rson);
    update(p);
}
void modify_cha(int le,int ri,int k,int s,int t,int p) {
    if(le<=s && t<=ri) {se[p].v=se[p].mx=k;return ;}
    int mid=(s+t)>>1;
    if(le<=mid) modify_cha(le,ri,k,lson);
    if(ri >mid) modify_cha(le,ri,k,rson);
    update(p);
}
ll query(int le,int ri,int s,int t,int p) {
    if(le<=s && t<=ri) return se[p].v;
    ll sum=0;
    int mid=(s+t)>>1;
    if(le<=mid) sum+=query(le,ri,lson);
    if(ri >mid) sum+=query(le,ri,rson);
    return sum;
}
int main(int argc, char const *argv[]) {
    n=rr(),m=rr();
    for(int i=1;i<=n;i++) {
        a[i]=rr();
    }
    build(1,n,1);
    while (m--) {
        int op=rr();
        if(op==1) {
            int le=rr(),ri=rr();
            std::cout << query(le,ri,1,n,1) << '\n';
        }
        else if(op==2) {
            int le=rr(),ri=rr(),k=rr();
            modify_mod(le,ri,k,1,n,1);
        }
        else if(op==3) {
            int x=rr(),k=rr();
            modify_cha(x,x,k,1,n,1);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值