[洛谷P3948]数据结构 题解(差分)

[洛谷P3948]数据结构

Description

最开始的数组每个元素都是0
给出n,opt ,min,max,mod 在int范围内
A: L ,R ,X 表示把[l,R] 这个区间加上X(数组的从L到R的每个元素都加上X)
Q : L ,R 表示询问[L,R] 这个区间中元素T满足 min<=(T∗i %mod)<=max 的 T这样的数的个数(i是数组下标)(元素的值*数组下标%mod在min到max范围内)

由于 edt 请来了一位非三次元的仓鼠,他帮你用延后了部分问题,将这些询问打入了混乱时空,你的询问操作>不会超过1000次,不幸的是,对于延后的询问操作可能有很多次(小于1e7次),但是保证这些延后的询问操作之后不会再次有修改操作(就是在最后会有很多次询问,但不会进行修改)

输入格式:
给出n,opt,mod,min,max表示序列大小,操作次数,取膜,最小值,最大值

下面opt行,给出
A : L ,R ,X 表示区间加,保证X在int范围内(<2147483647)
Q :L ,R 表示区间查询满足条件的个数

再给出一个Final 值,表示后面有Final 个询问
下面Final 行,给出
L,R 表示询问区间[L,R]之间满足条件的个数

输出格式:
每行对于每个Q 操作输出Q 个数表示每次询问的值,
下面Final 行表示Final个询问的值

Solution

1.首先因为前半部分以区间修改为主,所以我们采用差分的方法使该操作变为O(1),即对于每个L,R,X,令num[L]+=X,num[R+1]-=X;

2.由于前半部分寻问非常少(小于1000次)每次都计算一遍当前数组的各个数字,O(n)处理就好;

3.对于final部分的寻问,因为没有修改,我们考虑离线处理,先进行预处理,用一个数组ok[i]记录i即其以前的元素符合条件的个数,再对于每一个询问L,R,输出ok[R]-ok[L-1]的值即可(因为ok[R]统计的是R及其以前的符合条件的元素个数,减去不在区间[L,R]内的部分,即ok[L-1]就是区间内符合要求的元素个数);

Code

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;

long long num[100100],n,m,i,j,k,minn,maxn,mod,l,r,x,t,ok[100100];
char c;

inline long long rd(){
    long long x=0;
    bool f=true;
    char c;
    c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-') f=false;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=(x<<1)+(x<<3)+(c^48);
        c=getchar();
    }
    return f?x:-x;
} 

inline char getc()
{
    char c=getchar();
    while(c<'A'||c>'Z')c=getchar();
    return c;
}

void modify(){
    l=rd();
    r=rd();
    x=rd();
    num[l]+=x;
    num[r+1]-=x;
}

void count(){
    l=rd();
    r=rd();
    long long ans=0;
        x=0;
    for(i=1;i<=r;++i){
        x+=num[i];
        if(i>=l&&((x*i)%mod>=minn)&&((x*i)%mod<=maxn)) ++ans;
    }
    printf("%lld\n",ans);
}

int main(){
    memset(ok,0,sizeof(ok));
    memset(num,0,sizeof(num));
    n=rd();
    t=rd();
    mod=rd();
    minn=rd();
    maxn=rd();
    for(k=1;k<=t;++k){
        c=getc();
        if(c=='A') modify();
        else count(); 
    }
    t=rd();
    x=0;
    for(i=1;i<=n;++i){
        x+=num[i];
        ok[i]=ok[i-1];
        if(((x*i)%mod>=minn)&&((x*i)%mod<=maxn))++ok[i];
    }
    for(i=1;i<=t;++i){
        l=rd();
        r=rd();
        printf("%lld\n",ok[r]-ok[l-1]);
    }
    return 0;
}

差分数组的基础参考以前的随笔:http://www.cnblogs.com/COLIN-LIGHTNING/p/8436624.html

转载于:https://www.cnblogs.com/COLIN-LIGHTNING/p/8482463.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值