NYOJ-119-士兵杀敌(三)(线段树)

士兵杀敌(三)
时间限制: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
首先这题我推荐用RMQ算法,区间求最值。
但是为了练习一下刚学的线段树,还是勉强用线段树写了,第一次交超时,然后改为位运算,1800多毫秒,勉强通过。

由于需要求出最大和最小值,所以查找函数要定义成结构体,便于一次返回最大值和最小值

代码

#include<iostream>
#include<algorithm>
#include<math.h>
#include<string>
#include<string.h>
#include<stdio.h>
#include<queue>
using namespace std;
//线段树基本操作
//建立两个线段树
const int maxn=100005;
int N;//士兵总数
int Q;//查询次数
struct node
{
    int left;
    int right;
    int max_num;
    int min_num;
} Tree[maxn*4];
void Build(int root,int star,int end)
{
    Tree[root].left=star;
    Tree[root].right=end;
    if(star==end)
    {
        scanf("%d",&Tree[root].max_num);
        Tree[root].min_num=Tree[root].max_num;
        return;
    }
    int mid=(star+end)>>1;
    Build(root<<1,star,mid);
    Build(root<<1|1,mid+1,end);
    Tree[root].max_num=Tree[root<<1].max_num>Tree[root<<1|1].max_num?Tree[root<<1].max_num:Tree[root<<1|1].max_num;
    Tree[root].min_num=Tree[root<<1].min_num<Tree[root<<1|1].min_num?Tree[root<<1].min_num:Tree[root<<1|1].min_num;
}
node Find(int root,int star,int end)
{
    if(Tree[root].left==star&&Tree[root].right==end)
        return Tree[root];
    int mid=(Tree[root].left+Tree[root].right)>>1;
    if(end<=mid)
        return Find(root<<1,star,end);
    else if(star>mid)
        return Find(root<<1|1,star,end);
    else
    {
        node flag1=Find(root<<1,star,mid);
        node flag2=Find(root<<1|1,mid+1,end);
        node flag;
        flag.max_num=flag1.max_num>flag2.max_num?flag1.max_num:flag2.max_num;
        flag.min_num=flag1.min_num<flag2.min_num?flag1.min_num:flag2.min_num;
        return flag;
    }
}
int main()
{
    scanf("%d%d",&N,&Q);
    Build(1,1,N);//建立线段树
    int m,n;//查询区间范围
    while(Q--)
    {
        scanf("%d%d",&m,&n);
        node temp=Find(1,m,n);
        printf("%d\n",temp.max_num-temp.min_num);
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值