【线段树】奶牛排队(USACO 2007 January Gold)
Description
在每天挤奶的时候,农民约翰的N头牛(1≤n≤50000)总是排成一列。有一天,约翰决定与他的牛们一起玩一个极限飞盘游戏。为了简单起见,他将从奶牛队列里面选一定范围内的奶牛来玩这个游戏。然而所有的牛对这个游戏都很感兴趣。农民约翰列出了Q份名单(1≤Q≤200000)和每个奶牛的高度(1≤高度≤1000000)。对于每一份名单,他想你帮助他确定在每份名单中高度最高的奶牛与高度最低的奶牛的高度差是多少。
Input
第一行为N(1≤N≤50000)和Q(1≤Q≤200000);
从第2行到第N+1行,每行一个数字,表示第i头牛的高度(1≤height≤1000000);
从第N+2行到第N+Q+1行,每行两个整数A和B(1≤A≤B≤N),表示从第A头牛到第B头牛的范围。
Output
从第一行到第Q行,每行一个整数,表示从第A头牛到第B头牛之间,最高牛与最矮牛的高度差。
Sample Input
6 3
1
7
3
4
2
5
1 5
4 6
2 2
Sample Output
6
3
0
思路
- 大水题,普通线段树维护区间最大/最小值
代码
#include <iostream>
#include <cstdio>
#define maxn 50005
using namespace std;
int n,q,v[maxn];
struct fdfdfd{int l,r,maxx,minn;}a[maxn<<2];
void pushup(int x)
{
a[x].maxx=max(a[x<<1].maxx,a[x<<1|1].maxx);
a[x].minn=min(a[x<<1].minn,a[x<<1|1].minn);
}
void build(int x,int left,int right)
{
a[x].l=left; a[x].r=right;
if(left==right){a[x].maxx=a[x].minn=v[left]; return;}
int mid=(left+right)>>1;
build(x<<1,left,mid); build(x<<1|1,mid+1,right);
pushup(x);
}
fdfdfd query(int x,int left,int right)
{
if(a[x].r<left||a[x].l>right) return (fdfdfd){0,0,-1,0x7fffffff};
if(left<=a[x].l&&right>=a[x].r) return a[x];
fdfdfd temp1=query(x<<1,left,right),temp2=query(x<<1|1,left,right),temp;
temp.maxx=max(temp1.maxx,temp2.maxx);
temp.minn=min(temp1.minn,temp2.minn);
return temp;
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;++i) scanf("%d",&v[i]);
build(1,1,n);
while(q--)
{
int f1,f2; scanf("%d%d",&f1,&f2);
fdfdfd f3=query(1,f1,f2);
printf("%d\n",f3.maxx-f3.minn);
}
return 0;
}