POJ 3264 Balanced Lineup(线段树)

线段树第一题

输入n和m共有n个数,m个操作

在m个操作中输入a和b在a和b的范围中求出最大值减最小值的和

线段树区间更新问题,将num数组的数先放入到线段树里面的叶子节点,也就是说最底下一层从左到右按顺序就是num[i]的值

在build方法过程中从叶子节点开始向上更新,每两个节点取一个最大和最小

层层更新上去到了树根的时候就是第1个到第n个数的最大值和最小值

如果要具体查询a到b,其实就是查询线段为a到b的最大值减最小值

代码中根据习惯用到了位运算

i<<1就是2*i也就是左孩子序号

 i<<1就是2*i+1也就是右孩子序号

i>>1就是i/2其中

mid就是l和r的中点

上代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 50005
using namespace std;
struct node {
    int l, r, maxn, minn;
}tree[N<<2];
int max1,min1;
int num[N];
void build(int l,int r,int i)
{
    tree[i].l=l;
    tree[i].r=r;
    if(l==r)
    {
        tree[i].maxn=tree[i].minn=num[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,i<<1);
    build(mid+1,r,i<<1|1);
    tree[i].maxn=max(tree[i<<1].maxn,tree[i<<1|1].maxn);
    tree[i].minn=min(tree[i<<1].minn,tree[i<<1|1].minn);
}
void query(int l,int r,int i)
{
    if(l<=tree[i].l&&r>=tree[i].r)
    {
        min1=min(tree[i].minn,min1);
        max1=max(tree[i].maxn,max1);
        return ;
    }
    int mid=(tree[i].l+tree[i].r)>>1;
    if(mid<l)query(l,r,i<<1|1);
    else if(mid>=r)query(l,r,i<<1);
    else {
        query(l,r,i<<1);
        query(l,r,i<<1|1);
    }
}
int main()
{
    int n,m;
    int a,b;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&num[i]);
    build(1,n,1);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&a,&b);
        min1=99999999;
        max1=-99999999;
        query(a,b,1);
        printf("%d\n",max1-min1);
    }

    return 0;
}



猜你喜欢

转载自blog.csdn.net/dioml/article/details/50717328