差分与前缀和 POJ-3263 Tallest Cow

前缀和

前缀和顾名思义,最简单的一维前缀和就是类似于将一个数组
例如 1 2 3 4 5
按照1 3 6 10 15 的方式来存储
这样我们在求解类似于求数组前n个数的问题时时间复杂度仅仅为O(1)。
对于前缀和这里收藏了一篇博客讲的非常好

版权声明:本文为CSDN博主「Alex_McAvoy」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u011815404/article/details/88783231

差分

差分个人理解可以看作对于前缀和的一种应用(这里先只记录一维差分,后续再补)

当我们需要对一个数组进行多次变换时,例如要求将i-j元素增大2,再将h-q元素增大5…此时如果我们按照一般方法,进行变换每次都需要遍历数组进行运算,我们可以考虑换个思维,将从i开始的所有元素都+2,再将j后的元素全部-2,对于之后的运算也如此考虑,我们将新建一个数组p初始值为0,将p[i]记为+2,p[j+1]记为-2,之后的运算也如此操作,最后只需求p的前缀和,即p[i]=p[i]+p[i-1],即可得到最终的变化结果再与原数组相加即可这样的时间复杂度只有O(n);

下面链接同样是上面那个大佬的文章mark一下

版权声明:本文为CSDN博主「Alex_McAvoy」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u011815404/article/details/86375796

上个简单的例题

POJ-3263 Tallest Cow

Description

FJ’s N (1 ≤ N ≤ 10,000) cows conveniently indexed 1…N are standing in a line. Each cow has a positive integer height (which is a bit of secret). You are told only the height H (1 ≤ H ≤ 1,000,000) of the tallest cow along with the index I of that cow.
FJ has made a list of R (0 ≤ R ≤ 10,000) lines of the form “cow 17 sees cow 34”. This means that cow 34 is at least as tall as cow 17, and that every cow between 17 and 34 has a height that is strictly smaller than that of cow 17.
For each cow from 1…N, determine its maximum possible height, such that all of the information given is still correct. It is guaranteed that it is possible to satisfy all the constraints.

Input

Line 1: Four space-separated integers: N, I, H and R
Lines 2…R+1: Two distinct space-separated integers A and B (1 ≤ A, B ≤ N), indicating that cow A can see cow B.

Output

Lines 1…N: Line i contains the maximum possible height of cow i.

Sample Input

9 3 5 5
1 3
5 3
4 3
3 7
9 8

Sample Output

5
4
5
3
4
4
5
5
5

题目大意就是一堆奶牛(奇怪今天写了好几个奶牛题了…),站一排,A能看见B说明B至少和A一样高,而且A与B之间的奶牛都比A矮,告诉你四个数字分别是牛的个数,最高牛的高度,编号以及组合个数,让你求出所有牛的最大可能高度
先将所有母牛初始化为最大高度,因为求的是最大可能高度,所以其实就是将所有组合中A与B之间的牛出现一次就减一,最后统计减了多少,同初始数组相加即可,本质上就是对差分的应用。
需要注意的是
1、A与B大小关系不确定
2、A与B有可能重复出现,别计算重复了

对于第二点这里利用了map模板进行判重
AC代码如下:

#include //拆分 前缀和 
#include 
#include 
#include 
using namespace std;
map<pair<int,int>, bool>vis;//先定义类型
int p[10005];

void A(int a1,int a2){//创建并维持差分数组
	p[a1+1]-=1;
	p[a2]+=1;
}
void B(int n){//求差分数组前缀和
	for(int i=2;i<=n;i++){
		p[i]+=p[i-1];
	}
} 

int main(){
	int n,j,h,r,a1,a2;//n是牛的个数 i是最高牛编号 h是最高牛高度 r是组合个数 
	scanf("%d %d %d %d",&n,&j,&h,&r);
	memset(p,0,sizeof(p));
	for(int i=1;i<=r;i++){
		scanf("%d %d",&a1,&a2);
		if(vis[make_pair(a1,a2)]||vis[make_pair(a2,a1)]) continue;
		if(a1>a2) A(a2,a1);
		else if(a1<a2) A(a1,a2);
		vis[make_pair(a1,a2)]=1;//a1,a2组合出现一次将其标记,避免再次被计算
		vis[make_pair(a2,a1)]=1;//以防万一出现类似于(1,3),(3,1)这种数据,不过实测没有这句也能过
	}
	B(n);
	for(int i=1;i<=n;i++){
		printf("%d\n",h+p[i]);
	}
	return 0;
}

你可能感兴趣的:(差分法)