【Codeforces 483D】The Child and Sequence | 线段树、思维、数学技巧

题目链接:http://codeforces.com/contest/438/problem/D

题目大意:

给出一段序列

你需要执行三个操作:

1.求[l,r]的区间和

2.将[l,r]的所有数就对x取余

3.将第k个数赋值为x

题目思路:

其实这个题是队友甩给我的..

首先考虑到一个性质,取余会使得当前x/2

所以考虑到 洛谷开根的 题目

所以只需要维护一个最大值

然后与洛谷的题目一样直接暴力修改即可

复杂度保证可以在nlog2/n,因为每个数最多修改30次

就算有第三个操作,那么也是会增加一个logn的查询或者修改

所以总体复杂度也是:nlogn

Code:

#pragma GCC optimize(3)
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
typedef  long long ll;
using namespace std;
#define rep(i,j,n) for(ll i=j;i<=n;i++)
typedef unsigned long long ull;
const ll INF= 1e16;
const ll maxn = 3e6+7;
const ll mod = 1e9+7;
inline bool read(ll &num)
{char in;bool IsN=false;
    in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
ll num[maxn];
ll mx[maxn];
ll sum[maxn];
void push(int k){
    mx[k] = max(mx[k<<1],mx[k<<1|1]);
    sum[k] = sum[k<<1] + sum[k<<1|1];
}
void build(int k,int l,int r){

    if(l == r){
        mx[k] = num[l];
        sum[k] = num[l];
        return ;
    }
    int mid = (l+r)/2;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    push(k);

}
void ModifyOne(int k,int l,int r,int pos,ll w){
    if(l == r){
        mx[k] = w;
        sum[k] = w;
        return ;
    }
    int mid = (l+r)/2;
    if(pos<=mid) ModifyOne(k<<1,l,mid,pos,w);
    else ModifyOne(k<<1|1,mid+1,r,pos,w);
    push(k);
}
void Modify(int k,int l,int r,int x,int y,ll w){
    if(mx[k]<w) return;
    if(l == r){
        mx[k] = mx[k]%w;
        sum[k] = sum[k]%w;
        return;
    }
    int mid = (l+r)/2;
    if(x<=mid) Modify(k<<1,l,mid,x,y,w);
    if(y>mid) Modify(k<<1|1,mid+1,r,x,y,w);
    push(k);
    return;
}
ll Query(int k,int l,int r,int x,int y){
    if(x<=l&&y>=r) return sum[k];
    int mid = (l+r)/2;
    ll ans = 0;
    if(x<=mid) ans += Query(k<<1,l,mid,x,y);
    if(y>mid) ans += Query(k<<1|1,mid+1,r,x,y); 
    push(k);
    return ans;
}
int main(){

    read(n);read(m);
    for(int i=1;i<=n;i++) read(num[i]);
    build(1,1,n);
    for(int i=1;i<=m;i++){
        int op,x,y,z;scanf("%d",&op);
        if(op == 1){
            scanf("%d%d",&x,&y);
            printf("%lld\n",Query(1,1,n,x,y));
        }else if(op == 2){
            scanf("%d%d%d",&x,&y,&z);
            Modify(1,1,n,x,y,z);
        }else{
            scanf("%d%d",&x,&y);
            ModifyOne(1,1,n,x,y);
        }
    }
    return 0;
}
/***

***/


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只酷酷光儿( CoolGuang)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值