POJ - 3264 线段树模板题 询问区间最大最小值
这是线段树的一个模板题,给出一串数字,然后询问区间的最大最小值。
这个其实很好办,只需把线段树的节点给出两个权值,一个是区间的最小值,一个是区间的最大值,初始化为负无穷和正无穷,然后通过不断地输入节点,不断维护,最好每次询问维护一个询问区间的最大值和最小值,最后相减即可。其实就相当于,线段树找区间的最大值和最小值。
#include<iostream> #include<stdio.h> #include<algorithm> #include<string.h> #define INF 0x3f3f3f3f using namespace std; int minv=INF; int maxv=-INF; struct node{ int l,r; int minv,maxv; int mid()//中间值 { return (l+r)/2; } }tree[200010]; void buildtree(int root,int l,int r) { tree[root].l=l;//区间左边 tree[root].r=r;//区间右边 tree[root].minv=INF;//区间内部的最小值 tree[root].maxv=-INF;//区间内部的最大值 if(l!=r)//不是根节点 { buildtree(root*2+1,l,(l+r)/2); buildtree(root*2+2,(l+r)/2+1,r); } } void insert(int root,int i,int v){//单点修改 if (tree[root].l==tree[root].r) { tree[root].r=i; tree[root].minv=tree[root].maxv=v; return; } tree[root].minv=min(tree[root].minv,v);//不是根节点,那么当插入的数不断往下更新时,需要不断对树上的节点范围内的最大值和最小值进行更新 tree[root].maxv=max(tree[root].maxv,v); if(i<=tree[root].mid()) insert(2*root+1,i,v); else insert(2*root+2,i,v); } void query(int root,int s,int e) { if(tree[root].minv>minv && tree[root].maxv<maxv)//如果我前面维护的最小值已经比这一段的值还要小了,最大值也比这一段还要大了,那么无需再往下查询 return ; if(tree[root].l==s && tree[root].r==e)//维护最大值和最小值 { minv=min(minv,tree[root].minv); maxv=max(maxv,tree[root].maxv); return; } if(e<=tree[root].mid())//如过给出询问的区间不能通过一分为二分开,仍在区间的左边 query(2*root+1,s,e);//仍然继续递归这个区间 else if (s>tree[root].mid()) query(2*root+2,s,e);//反之也继续递归这个区间 else//需要把区间分开 { query(2*root+1,s,tree[root].mid());//对半分 query(2*root+2,tree[root].mid()+1,e); } } int main(){ int n,q,h; scanf("%d%d",&n,&q); buildtree(0,1,n); for (int i=1;i<=n;i++){ scanf("%d",&h); insert(0,i,h); } for (int i=0;i<q;i++) { int s,e; scanf("%d%d",&s,&e); minv=INF; maxv=-INF; query(0,s,e); printf("%d\n",maxv-minv); } return 0; }
有不懂欢迎咨询
QQ:1326487164(添加时记得备注)