1. 程式人生 > >nyoj 119士兵殺敵(三)(線段樹區間最值查詢,RMQ算法)

nyoj 119士兵殺敵(三)(線段樹區間最值查詢,RMQ算法)

信息 include out online log 每次 left 一行 [0

士兵殺敵(三)

時間限制:2000 ms | 內存限制:65535 KB 難度:5
描寫敘述

南將軍統率著N個士兵,士兵分別編號為1~N,南將軍常常愛拿某一段編號內殺敵數最高的人與殺敵數最低的人進行比較,計算出兩個人的殺敵數差值。用這樣的方法一方面能鼓勵殺敵數高的人,還有一方面也算是批評殺敵數低的人,起到了非常好的效果。

所以,南將軍常常問軍師小工第i號士兵到第j號士兵中,殺敵數最高的人與殺敵數最低的人之間軍功差值是多少。

如今,請你寫一個程序,幫小工回答南將軍每次的詢問吧。

註意,南將軍可能詢問非常多次。

輸入
僅僅有一組測試數據
第一行是兩個整數N,Q。當中N表示士兵的總數。Q表示南將軍詢問的次數。

(1<N<=100000,1<Q<=1000000)
隨後的一行有N個整數Vi(0<=Vi<100000000)。分別表示每一個人的殺敵數。


再之後的Q行。每行有兩個正正數m,n。表示南將軍詢問的是第m號士兵到第n號士兵。

輸出
對於每次詢問。輸出第m號士兵到第n號士兵之間全部士兵殺敵數的最大值與最小值的差。
例子輸入
5 2
1 2 6 9 3
1 2
2 4
例子輸出
1
7
來源

source=%E7%BB%8F%E5%85%B8%E6%94%B9%E7%BC%96" style="text-decoration:none; color:rgb(55,119,188)">經典改編

上傳者
張雲聰

看到這種題就想到線段樹 唉 還是知道的算法太少了

第一次線段樹還超時了(粗心 忘記寫return 了)

還能夠用RMQ算法(比線段樹快多了。。) 。百度的。

。。

線段樹 1836ms 險過。

。。

 
#include <stdio.h>
#include <algorithm>
using namespace std;
struct node
{
	int left,right;
	int max_num,min_num;
}tree[100000*4];
void build(int left,int right,int root)
{
	tree[root].left=left;
	tree[root].right=right;
	if(left==right)
	{
		scanf("%d",&tree[root].max_num);
		tree[root].min_num=tree[root].max_num;
		return ;
	}
	else
	{
		int mid=(left+right)/2;
		build(left,mid,root*2);
		build(mid+1,right,root*2+1);
		tree[root].max_num=max(tree[root*2].max_num,tree[root*2+1].max_num);
		tree[root].min_num=min(tree[root*2].min_num,tree[root*2+1].min_num);
	}
}
void search(int l,int r,int root,int &c,int &d)
{
	if(tree[root].left==l&&tree[root].right==r)
	{
		c=tree[root].max_num;
		d=tree[root].min_num;
		return ;
	}
	int mid=(tree[root].left+tree[root].right)/2;
	if(mid>=r)
	search(l,r,root*2,c,d);
	else if(mid<l)
	search(l,r,root*2+1,c,d);
	else
	{
		int c1,d1;
		search(l,mid,root*2,c,d);
		search(mid+1,r,root*2+1,c1,d1);
		c=max(c,c1);
		d=min(d,d1);
	}
}
int main()
{
	int n,k;
	scanf("%d %d",&n,&k);
	build(1,n,1);
	for(int i=0;i<k;i++)
	{
		int a,b;
		int c,d;
		scanf("%d %d",&a,&b);
		search(a,b,1,c,d);
		printf("%d\n",c-d);
	}
}        

RMQ算法 976ms 節省了近一倍的事件。

假設不懂RMQ (Range Minimum/Maximum Query)算法

點擊打開鏈接我轉載的小牛一篇文章

#include <stdio.h>
#include <algorithm>
#include <math.h>
using namespace std;
int min_num[100005][20];
int max_num[100005][20];
int n,k;
void RMQ()
{
	for(int i=1;i<20;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(j+(1<<i)-1<=n)
			{
				max_num[j][i]=max(max_num[j][i-1],max_num[j+(1<<(i-1))][i-1]);
				min_num[j][i]=min(min_num[j][i-1],min_num[j+(1<<(i-1))][i-1]);
			}
		}
	}
	
}
int main()
{
	scanf("%d %d",&n,&k);
	for(int i=1;i<=n;i++)
	{
		int x;
		scanf("%d",&x);
		min_num[i][0]=max_num[i][0]=x;
	}
	RMQ();
	for(int i=0;i<k;i++)
	{
		int a,b;
		scanf("%d %d",&a,&b);
		int pos=(int)(log(b-a+1.0)/log(2.0));
		int max1=max(max_num[a][pos],max_num[b-(1<<pos)+1][pos]);
		int min1=min(min_num[a][pos],min_num[b-(1<<pos)+1][pos]);
		printf("%d\n",max1-min1);
	}
	return 0;
}



nyoj 119士兵殺敵(三)(線段樹區間最值查詢,RMQ算法)