加农炮 51Nod - 1287(线段树)

一个长度为M的正整数数组A,表示从左向右的地形高度。测试一种加农炮,炮弹平行于地面从左向右飞行,高
度为H,如果某处地形的高度大于等于炮弹飞行的高度H(Ai >= H),炮弹会被挡住并落在i - 1处,则Ai−1 + 1。
如果H <= A0,则这个炮弹无效,如果H > 所有的Ai,这个炮弹也无效。现在给定N个整数的数组B代表炮弹高
度,计算出最后地形的样子。例如:地形高度A = {1, 2, 0, 4, 3, 2, 1, 5, 7}, 
炮弹高度B = {2, 8, 0, 7, 6, 5, 3, 4, 5, 6, 5},最终得到的地形高度为:{2, 2, 2, 4, 3, 3, 5, 6, 7}。 

Input:

第1行:2个数M, N中间用空格分隔,分别为数组A和B的长度(1 <= m, n <= 50000)
第2至M + 1行:每行1个数,表示对应的地形高度(0 <= Ai <= 1000000)。
第M + 2至N + M + 1行,每行1个数,表示炮弹的高度(0 <= Bi <= 1000000)。

Output:

输出共M行,每行一个数,对应最终的地形高度。

Sample Input:

9 11
1
2
0
4
3
2
1
5
7
2
8
0
7
6
5
3
4
5
6
5

Sample Output:

2
2
2
4
3
3
5
6
7

思路:

这个题数据给的不严,暴力有很多种方法可以跑过去,不过还是推荐线段树。

没啥坑点,就是注意点更新。

因为找到的点往往是第一个>=炮弹的点而要更新的是前一个点。不能直接通过下标减一来更新。

因为会有几种特殊情况:


如图中的【4,4】点和【2,2】点还有【6,6】点和【5,5】 点,后一个点无法通过下标减一来找到前一个点。

所以推荐用数组记录下每个叶子对应的下标。

代码:

#include<stdio.h>
#include<iostream>
#include<queue>
#include<cstring>
#include<cmath>

using namespace std;

int board[50005][2];//存地形高度和对应的在map里的下标 

int map[700005];
int m,n;

void Build(int head,int tail,int now)
{
	if(head == tail)
	{
		map[now] = board[head][0];
		board[head][1] = now;
		return ;
	}
	int mid = (head+tail)/2;
	Build(head,mid,now<<1);
	Build(mid+1,tail,now<<1|1);

	map[now] = max(map[now<<1],map[now<<1|1]);
}

void p(int now) //用于叶结点更新后更新线段树 
{
	if(now == 1)return ;
	if(now&1)
	{
		if(map[now]>map[(now-1)/2])
		{
			map[(now-1)/2] = map[now];
			p((now-1)/2);
		}
	}
	else
	{
		if(map[now]>map[now/2])
		{
			map[now/2] = map[now];
			p(now/2);
		}
	}
}

void Updata(int head,int tail,int now,int val)
{
	if(head == tail)
	{
		if(head == 1)return;
		board[head-1][0]++;
		map[board[head-1][1]] = board[head-1][0];
		p(board[head-1][1]);
		return ;
	}

	int mid = (head+tail)/2;
	if(map[now<<1]>=val)Updata(head,mid,now<<1,val);
	else Updata(mid+1,tail,now<<1|1,val);

}


int main()
{
	scanf("%d %d",&m,&n);
	for(int i=1 ; i<=m ; i++)
	{
		scanf("%d",&board[i][0]);
	}

	Build(1,m,1);

	while(n--)
	{
		int mid;
		scanf("%d",&mid);
		if(mid>map[1])continue;
		Updata(1,m,1,mid);
	}
	
	for(int i=1 ; i<m ; i++)printf("%d\n",board[i][0]);
	printf("%d",board[m][0]);
	
	return 0;
}


posted @ 2017-08-14 19:35  Assassin_poi君  阅读(118)  评论(0编辑  收藏  举报