线段树的维护,以及运用(POJ3264)

线段树的常规操作,可以维护最大值,最小值,区间和。
而线段树的相关实现不仅能用数组,也经常使用结构体。
题目来源:http://poj.org/problem?id=3264

每天挤奶时,农夫John的N头奶牛(1≤N≤50,000头)总是按照相同的顺序排列。一天,农夫约翰决定和几头牛组织一场极限飞盘游戏。为了简单起见,他将从挤奶阵容中挑选一系列连续的奶牛来玩这个游戏。然而,为了让所有的奶牛都能玩得开心,它们的身高不应该相差太多。
农民John列出了Q(1≤Q≤200,000)头奶牛的身高(1≤身高≤1,000,000)。对于每一组,他希望您确定组中最矮和最高的牛之间的身高差异。

Input
第一行:两个空格分隔的整数N和Q
第二行到第N+1行:第i+1行包含一个整数,表示第i头奶牛的高度
第N+2行到第N+Q+1行:每行包含空格隔开的两个整数A、B(1≤A≤B≤N),表示奶牛从A到B的范围

Output
每行包含一个整数,是对每组范围的回答,表示范围内最高和最矮奶牛之间的高度差

Sample Input
6 3
1
7
3
4
2
5
1 5
4 6
2 2

Sample Output
6
3
0
要求同时维护最大值和最小值,所以用结构体更加方便。

struct node{
int minn;
int maxx;
}tree[maxn*4];
建树:
void build(int root,int l,int r){
if(l==r)
tree[root].minn=tree[root].maxx=arr[l];
else{
int mid=(l+r)/2;
int lson=root*2;
int rson=root*2+1;
build(lson,l,mid);
build(rson,mid+1,r);
tree[root].maxx=max(tree[lson].maxx,tree[rson].maxx);
tree[root].minn=min(tree[lson].minn,tree[rson].minn);
    }
}
没有更新操作,不用写,直接查询
ll query(int root,int l,int r,int L,int R,int fla){//fla是开口,方便查询最大和最小,就没必要写两个函数
if(fla){
if(L<=l&&R>=r)
  return tree[root].max;
  int mid=(l+r)/2;
  int lson=root*2;
  int rson=root*2+1;
  ll sum1=0,sum2=0;
  if(L<=mid)
   sum1=query(lson,l,mid,L,R,fla);
   if(R>mid)
   sum2=query(rson,mid+1,r,L,R,fla);
   return max(sum1,sum2);
}
else{
if(L<=l&&R>=r)
  return tree[root].max;
  int mid=(l+r)/2;
  int lson=root*2;
  int rson=root*2+1;
  ll sum1=0,sum2=0;
  if(L<=mid)
   sum1=query(lson,l,mid,L,R,fla);
   if(R>mid)
   sum2=query(rson,mid+1,r,L,R,fla);
   return min(sum1,sum2);
   }
}
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define rep(i,a,b)for(int i=a;i<=b;i++)
#define rep1(i,a,b)for(int i=a;i<b;i++)
using namespace std;
const int maxn=2e6+5;
 const int INF = 1e9;
int n,m;
int L,R;
int arr[maxn];
struct node{
    int maxx;
    int minn;
}tree[4*maxn];

void build(int root,int l,int r){
if(l==r)
tree[root].minn=tree[root].maxx=arr[l];
else{
int mid=(l+r)/2;
int lson=root*2;
int rson=root*2+1;
build(lson,l,mid);
build(rson,mid+1,r);
tree[root].maxx=max(tree[lson].maxx,tree[rson].maxx);
tree[root].minn=min(tree[lson].minn,tree[rson].minn);
    }
}

ll query(int root,int l,int r,int L,int R,int fla){//fla是开口,方便查询最大和最小,就没必要写两个函数
if(fla){
if(L<=l&&R>=r)
  return tree[root].max;
  int mid=(l+r)/2;
  int lson=root*2;
  int rson=root*2+1;
  ll sum1=0,sum2=0;
  if(L<=mid)
   sum1=query(lson,l,mid,L,R,fla);
   if(R>mid)
   sum2=query(rson,mid+1,r,L,R,fla);
   return max(sum1,sum2);
}
else{
if(L<=l&&R>=r)
  return tree[root].max;
  int mid=(l+r)/2;
  int lson=root*2;
  int rson=root*2+1;
  ll sum1=0,sum2=0;
  if(L<=mid)
   sum1=query(lson,l,mid,L,R,fla);
   if(R>mid)
   sum2=query(rson,mid+1,r,L,R,fla);
   return min(sum1,sum2);
   }
}

int main(){
    //int cnt=1;
    scanf("%d%d",&n,&m);
    rep(i,1,n)
    scanf("%d",&arr[i]);
    build(1,1,n);
    while(m--){
        int x,y;
        scanf("%d%d",&x,&y);
        printf("%d\n",query(1,1,n,x,y,1)-query(1,1,n,x,y,0));
    
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值