zoukankan      html  css  js  c++  java
  • [洛谷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
    ",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
    ",ok[r]-ok[l-1]);
    	}
    	return 0;
    }
    

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

  • 相关阅读:
    Linux系统常用工具集
    Storm安装部署
    Linux下搭建Elasticsearch7.6.2集群
    解决SpringMVC @RequestBody无法注入基本数据类型
    微服务概念
    HashMap的原理简单介绍
    mysql进阶
    vue 路由缓存 keep-alive include和exclude无效
    el-date-picker 时间日期格式,选择范围限制
    RedisTemplate使用rightPushAll往list中添加时的注意事项
  • 原文地址:https://www.cnblogs.com/COLIN-LIGHTNING/p/8482463.html
Copyright © 2011-2022 走看看