POJ - 3264 Balanced Lineup 线段树解RMQ

时间:2022-05-30 20:23:13

这个题目是一个典型的RMQ问题,给定一个整数序列,1~N,然后进行Q次询问,每次给定两个整数A,B,(1<=A<=B<=N),求给定的范围内,最大和最小值之差。

解法一:这个是最初的解法,时间上可能会超时,下面还有改进算法.4969ms

 #include<stdio.h>
#include<stdlib.h>
#define INF 1000010
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)>(b)?(b):(a)) typedef struct res
{
int mx,mi;
} pair; typedef struct node
{
struct node *lc,*rc;
int ld,rd;
pair res;
} node; node *buildTree(int a,int b)
{
node*p=(node*)malloc(sizeof(node));
p->ld=a;
p->rd=b;
p->res.mx=;
p->res.mi=INF;
p->lc=p->rc=NULL;
if(a==b)
return p;
p->lc=buildTree(a,(a+b)>>);
p->rc=buildTree(((a+b)>>)+,b);
return p;
} void insert(node*T,int pos,int key)
{
int mid=(T->rd+T->ld)>>;
if(T->rd==T->ld)
{
T->res.mx=T->res.mi=key;
return;
}
if(pos<=mid)
insert(T->lc,pos,key);
else insert(T->rc,pos,key);
T->res.mx=max(T->lc->res.mx,T->rc->res.mx);
T->res.mi=min(T->lc->res.mi,T->rc->res.mi);
return;
} pair search(node*T,int a,int b)
{
pair temp1,temp2,ans;
int mid=(T->rd+T->ld)>>; temp1.mx=temp2.mx=;
temp1.mi=temp2.mi=INF;
if(a<=T->ld&&T->rd<=b)
return T->res;
if(a<=mid)
temp1=search(T->lc,a,b);
if(b>mid)
temp2=search(T->rc,a,b);
ans.mx=max(temp1.mx,temp2.mx);
ans.mi=min(temp1.mi,temp2.mi);
return ans;
} int main(void)
{
int n,q,i,a,b;
pair ans;
scanf("%d%d",&n,&q);
node *head=buildTree(,n);
for(i=; i<=n; i++)
{
scanf("%d",&a);
insert(head,i,a);
}
for(i=; i<=q; i++)
{
scanf("%d%d",&a,&b);
ans=search(head,a,b);
printf("%d\n",ans.mx-ans.mi);
}
return ;
}

解法二:

利用数组的形式:3704ms

 #include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define N 1000010
#define INF 1000010
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)>(b)?(b):(a)) int l[N],r[N],i,n;
typedef struct
{
int mx,mi;
} pair;
pair res[N]; void BuildTree(int x,int y,int p)
{
l[p]=x;
r[p]=y;
if(x==y)
return;
BuildTree(x,(x+y)>>,*p);
BuildTree(((x+y)>>)+,y,*p+);
} void Insert(int num,int p)
{
int mid=(l[p]+r[p])>>;
res[p].mx=max(res[p].mx,num);
res[p].mi=min(res[p].mi,num);
if(l[p]==r[p])
return;
if(i<=mid)
Insert(num,*p);
else Insert(num,*p+);
} pair search(int x,int y,int p)
{
pair a1,a2,ans;
a1.mx=a2.mx=;
a1.mi=a2.mi=INF;
int mid=(l[p]+r[p])>>;
if(x<=l[p]&&y>=r[p])
return res[p];
if(x<=mid)
a1=search(x,y,*p);
if(y>mid)
a2=search(x,y,*p+);
ans.mx=max(a1.mx,a2.mx);
ans.mi=min(a1.mi,a2.mi);
return ans;
} int main(void)
{
int q,j,x,y;
pair ans;
memset(res,,sizeof(res));
scanf("%d%d",&n,&q);
BuildTree(,n,);
for(i=; i<N; i++)
res[i].mi=INF;
for(i=; i<=n; i++)
{
scanf("%d",&j);
Insert(j,);
} for(i=; i<q; i++)
{
scanf("%d%d",&x,&y);
ans=search(x,y,);
printf("%d\n",ans.mx-ans.mi);
}
return ;
}

解法三:

这是利用别人的算法改进而来,所以有时候多借鉴别人的代码,并且可以和自己的想法结合起来,效果还不错.

 #include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define N 50010
#define INF 1000010
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)>(b)?(b):(a)) typedef struct
{
int l,r;
int mx,mi;
} pair;
pair temp[N*];
int Max,Min; void BuildTree(int x,int y,int p)
{
temp[p].l=x;
temp[p].r=y;
temp[p].mx=;
temp[p].mi=INF;
if(x==y)
return;
int mid=(x+y)/;
BuildTree(x,mid,p*);
BuildTree(mid+,y,*p+);
} void Insert(int v,int num,int p)
{
if(temp[v].l==temp[v].r)
{
temp[v].mx=temp[v].mi=num;
return ;
}
int mid=(temp[v].r+temp[v].l)/;
if(p<=mid)
{
Insert(*v,num,p);
temp[v].mx=max(temp[v].mx,temp[*v].mx);
temp[v].mi=min(temp[v].mi,temp[*v].mi);
}
else
{
Insert(*v+,num,p);
temp[v].mx=max(temp[v].mx,temp[*v+].mx);
temp[v].mi=min(temp[v].mi,temp[*v+].mi);
}
} void search(int x,int y,int p)
{
if(temp[p].l==x&&temp[p].r==y)
{
Max=max(Max,temp[p].mx);
Min=min(Min,temp[p].mi);
return;
}
int mid=(temp[p].l+temp[p].r)/;
if(x>mid)
{
search(x,y,*p+);
}
else if(y<=mid)
{
search(x,y,*p);
}
else
{
search(x,mid,*p);
search(mid+,y,*p+);
}
return;
} int main(void)
{
int n,q,i,x,y;
scanf("%d%d",&n,&q);
BuildTree(,n,);
for(i=;i<=n;i++)
{
scanf("%d",&x);
Insert(,x,i);
}
for(i=;i<q;i++)
{
scanf("%d%d",&x,&y);
Max=;
Min=INF;
search(x,y,);
printf("%d\n",Max-Min);
}
return ;
}