南阳acm士兵杀敌(三)(线段树)

士兵杀敌(三)

时间限制: 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 21 2 6 9 31 22 4
样例输出
17

#include <iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct Max//记录最大最小
{
int max1;
int min1;
};
struct Tree
{
int l,r;//左右子树
Max num;//记录最大最小。
}map1[440000];
int a[100005];//记录每个士兵杀的人数。
void Builer(int l,int r,int q)//建树
{
map1[q].l=l;
map1[q].r=r;
map1[q].num.max1=0;
map1[q].num.min1=0;
if(l==r)
{
map1[q].num.max1=a[l];//只有叶子节点上面才有杀的人数。
map1[q].num.min1=a[l];
return ;
}
int mid=(l+r)/2;
Builer(l,mid,q*2);
Builer(mid+1,r,q*2+1);
}
void shangfu(int l,int r,int q)//上浮
{
if(l==r)
{
return ;
}
int mid=(l+r)/2;
shangfu(l,mid,q*2);
shangfu(mid+1,r,q*2+1);
map1[q].num.max1=max(map1[q*2].num.max1,map1[q*2+1].num.max1);//当前节点的最大最小值是从左右子树求出来的。
map1[q].num.min1=min(map1[q*2].num.min1,map1[q*2+1].num.min1);
}
Max find1(int l,int r,int q)
{

if(l<=map1[q].l&&r>=map1[q].r)//找到区间[l,r]返回最大值最小值
{
return map1[q].num;
}
else if(r<=map1[q*2].r)//区间[l,r]区间属于左子树。
{
return find1(l,r,q*2);
}
else if(l>=map1[q*2+1].l) //区间[l,r]区间属于右子树
{
return find1(l,r,q*2+1);
}
else//区间[l,r]属于左右子树
{
int mid=(map1[q].l+map1[q].r)/2;
Max b,c,d;
c=find1(l,mid,q*2);
d=find1(mid+1,r,q*2+1);
b.max1=max(c.max1,d.max1);
b.min1=min(c.min1,d.min1);
return b;
}
}
int main()
{
int m,n;
scanf("%d%d",&m,&n);

for(int i=1;i<=m;i++)
{
scanf("%d",&a[i]);
}
int b,c;
Builer(1,m,1);//建树
shangfu(1,m,1);
for(int i=0;i<n;i++)
{
scanf("%d%d",&b,&c);
Max d=find1(b,c,1);
printf("%d\n",d.max1-d.min1);
}
return 0;

}

相关文章
相关标签/搜索