差分与前缀和

Posted 行码棋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了差分与前缀和相关的知识,希望对你有一定的参考价值。

前置知识

前缀和

一维前缀和:

s [ i ] = a [ 1 ] + a [ 2 ] + . . . + a [ i ] s[i]=a[1]+a[2]+...+a[i] s[i]=a[1]+a[2]+...+a[i]

初始化:

for(int i=1;i<=n;i++)
	s[i] = s[i-1] + a[i];

二维前缀和:

s [ i ] [ j ] s[i][j] s[i][j] : 第i行第j列左上部分所有元素的和

( x 1 , y 1 ) (x_1, y_1) (x1,y1)为左上角, ( x 2 , y 2 ) (x_2, y_2) (x2,y2)为右下角的子矩阵的和为:

矩阵长宽都为1
s [ x 2 ] [ y 2 ] − s [ x 2 − 1 ] [ y 2 ] − s [ x 2 ] [ y 2 − 1 ] + s [ x 2 − 1 ] [ y 2 − 1 ] s[x2][y2] - s[x2 - 1][ y2] - s[x2][ y2 - 1] + s[x2 - 1][ y2 - 1] s[x2][y2]s[x21][y2]s[x2][y21]+s[x21][y21]
矩阵长宽都为k
s [ x 2 ] [ y 2 ] − s [ x 2 − k ] [ y 2 ] − s [ x 2 ] [ y 2 − k ] + s [ x 2 − k ] [ y 2 − k ] s[x2][y2] - s[x2 - k][ y2] - s[x2][ y2 - k] + s[x2 - k][ y2 - k] s[x2][y2]s[x2k][y2]s[x2][y2k]+s[x2k][y2k]

差分

差分数组b[i]代表a[i]-a[i-1]两个元素之间的差

给区间 [ l , r ] [l, r] [l,r]中的每个数加上c
b [ l ] + = c , b [ r + 1 ] − = c b[l] += c, b[r + 1] -= c b[l]+=c,b[r+1]=c

两者结合

差分数组b[i]=a[i]-a[i-1]
差分前缀和数组s[i]=s[i-1]+b[i]
做区间修改时一直进行差分数组的操作,最后统计时利用差分数组计算差分前缀和
注意是差分前缀和,是最后一个值与前面初始值之间(初始值如果用的是0,则表示当前值)的差距,而不是真正的前缀和。
s [ i ] = s [ i − 1 ] + b [ i ] s[i] = s[i-1] + b[i] s[i]=s[i1]+b[i]
s [ i ] s[i] s[i]为区间修改之后的a[i]


题目

蓝彗星

链接:
https://ac.nowcoder.com/acm/contest/23479/C


s1[i]:代表B的差分
s2[i]:代表R的差分

对差分求前缀和得到的是当前值,如果当前值为正说明存在,为0说明不存在

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5; 

int main()

	vector<int>s1(N,0),s2(N,0);
	int n,t;
	cin>>n>>t;
	string s;
	cin>>s;
	for(int i=1;i<=n;i++)
	
		int x;cin>>x;
		if(s[i-1]=='B') s1[x]++, s1[x+t]--;
		else s2[x]++, s2[x+t]--;
	
	int res = 0;
	for(int i=1;i<=2e5;i++)
	
		s1[i] += s1[i-1];
		s2[i] += s2[i-1];
		res += (s1[i] && !s2[i]);
	
	cout<<res<<endl;
	return 0;
  

把它当成思维题来写:
bl,br为B的左右区间
R只负责对B的区间进行切割

#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef long long ll;
const int N = 1e5+5;
pair<int,char>p[N];

int main()

	int n,k;
	cin>>n>>k;
	
	for(int i=1;i<=n;i++) cin>>p[i].se;
	for(int i=1;i<=n;i++) cin>>p[i].fi;
	sort(p+1,p+1+n);
	
	ll res = 0;
	int bl = 0,br = 0;
	int rl=0,rr=0;
	
	for(int i=1;i<=n;i++)
	
		if(p[i].se == 'B') //yanxu jisuan 
		
			if(p[i].fi>br)
			
				res += max(br-bl,0);
				bl = max(rr,p[i].fi);
				br = p[i].fi + k;
			
			else br = max(p[i].fi + k,br);
		
		
		if(p[i].se == 'R')//qiege
		
			br = min(p[i].fi,br);
			rr = max(rr,p[i].fi + k);
		
//		cout<<bl<<"--"<<br<<endl;
	
	if(bl and br) res += max(br-bl,0);
	cout<<res<<endl;
	return 0;

以上是关于差分与前缀和的主要内容,如果未能解决你的问题,请参考以下文章

差分与前缀和 Extra

差分与前缀和 Extra

前缀和差分模板

差分与前缀和

前缀和和差分模板(AcWing 795-798)

二维差分