【题解】洛谷P3948 数据结构 差分数组

本文深入探讨差分数组的概念及应用,通过实例说明如何利用差分数组进行区间加法操作,以及如何快速查询区间内特定条件的元素数量。文章还提供了一段AC代码,展示了差分数组在解决复杂区间问题上的高效性和灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:
https://www.luogu.org/problem/P3948

先上一个差分数组的简介:
例如给出一个数组a[n]={0,1,3,6,4,8,2}
则差分数组d[n]={0,1,2,3,-2,4,-6}
(感觉上a[0]和d[0]一直都是将它默认为0,从下标1开始复制)

d[1]=a[1]-a[0]
d[2]=a[2]-a[1]
d[3]=a[3]-a[2]

d[n]=a[n]-a[n-1]

在这里先简单介绍一下差分数组:
数组a[7]={0,1,3,6,4,8,2}
则差分数组d[7]={0,1,2,3,-2,4,-6}
(感觉上a[0]和d[0]一直都是将它默认为0,从下标1开始复制)

d[1]=a[1]-a[0]
d[2]=a[2]-a[1]
d[3]=a[3]-a[2]

d[n]=a[n]-a[n-1]

性质①:a[i]=d[i]前缀和
a[1]=d[0]+d[1]
a[2]=d[0]+d[1]+d[2]
a[3]=d[0]+d[1]+d[2]+d[3]

a[n]=d[0]+d[1]+…+d[n-1]+d[n]

性质②
如果我们要对某个区间都+x,还是以上一个例子为例
数组a[7]={0,1,3,6,4,8,2}
差分数组d[7]={0,1,2,3,-2,4,-6}

若我们对a[2]-a[5]都+1,则有变化后的数组:
a[7]={0,1,4759,2}
d[7]={0,1,3,3,-2,4,-7}
然后我们可以发现两个数组中变化了的只有加粗了的元素
在差分数组中d[2]=原d[2]+1,d[6]=原d[6]-1;
总结归纳就是:
若我们对数组a[n]的区间[l,r]+x;
对于差分数组d[n]的变化就是d[l]+=x,d[r+1]-=x;

对于本题:
前opt个操作:
用上面的性质②进行操作A
用性质①进行操作Q

后final个询问操作:
为了不t
先用性质①根据差分数组求出原值数组
然后对符合条件 min<=(T*imin<=(T∗i% mod)<=maxmod)<=max 进行记录
这样就可以每个询问都直接d[r]-d[l-1]了 //偷懒了直接用了差分数组来记录,这里可以再开一个数组的

ac代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+10;
ll d[maxn],sum[maxn];
int n,opt,mod,minn,maxx,l,r,x;

int main(){
	while(~scanf("%d%d%d%d%d",&n,&opt,&mod,&minn,&maxx)){
		while(opt--){
			char c[10];
			scanf("%s",c);
			if(c[0]=='A'){
				scanf("%d%d%d",&l,&r,&x);
				d[l]+=x;							//性质②
				d[r+1]-=x;
			}else if(c[0]=='Q'){
				scanf("%d%d",&l,&r);
				int cnt=0;
				for(int i=1;i<=r;i++){
					sum[i]=d[i]+sum[i-1];   //性质①
					if(i>=l&&sum[i]*i%mod>=minn&&sum[i]*i%mod<=maxx){
						cnt++;
					}
				}
				printf("%d\n",cnt);
			}
		}
		
		//用性质①根据差分数组求出原值
		for(int i=1;i<=n;i++){
			sum[i]=d[i]+sum[i-1];
		}
		
		//记录符合条件的
		for(int i=1;i<=n;i++){
			sum[i]=sum[i]*i%mod;
			if(sum[i]>=minn&&sum[i]<=maxx){
				d[i]=d[i-1]+1;
			}else{
				d[i]=d[i-1];
			}
		}
		
		int t;
		scanf("%d",&t);
		while(t--){
			scanf("%d%d",&l,&r);
			printf("%d\n",d[r]-d[l-1]);		//直接查询
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值