您的位置:首页 > 其它

poj3264——Balanced Lineup(ST算法及线段树操作)

2010-09-28 16:09 295 查看
dp[i][j]
表示
[i,j]
区间内的最小值,则


dp[i][i]=a[i]





dp[i][j]=min{dp[i][j-1],dp[i+2^(j-1)][j-1]}。



如果询问区间为
[s,t]


则只需要取
k=(int)log2(t-
s+1)


RMQ[s,t]=min{dp[s][k],dp[t-2^k+1][k]}。

#include<stdio.h>
#include<string.h>
#include<math.h>
#define max 500005
int a[max];
int fmin[max][50],fmax[max][50];
int n,q;
int f_min(int a,int b)
{
return a<b?a:b;
}
int f_max(int a,int b)
{
return a>b?a:b;
}
void st()
{
int m,i,j,k;
k=(int)(log((double)(n))/log(2.0));
for(j=1;j<=k;j++)
{
for(i=1;i+(1<<j)-1<=n;i++)
{
fmin[i][j]=f_min(fmin[i][j-1],fmin[i+(1<<(j-1))][j-1]);
fmax[i][j]=f_max(fmax[i][j-1],fmax[i+(1<<(j-1))][j-1]);
}
}
}
int find(int a,int b)
{
int fax,fin,k;
k=(int )(log((double)(b-a+1))/log(2.0));
fax=f_max(fmax[a][k],fmax[b-(1<<k)+1][k]);
fin=f_min(fmin[a][k],fmin[b-(1<<k)+1][k]);
return fax-fin;
}
int main()
{
int i;
scanf("%d%d",&n,&q);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
fmin[i][0]=a[i];
fmax[i][0]=a[i];
}
st();
while(q--)
{
int a,b;
scanf("%d%d",&a,&b);
printf("%d/n",find(a,b));
}
return 0;
}


此题,还可以运用线段树来求得,贴上刚学的线段树ac代码:
#include<stdio.h>
#include<string.h>
#define MAX 0
#define MIN 1000000
struct node
{
int left,right;
int min,max;
}tree[150000];
int n,min,max;
void create(int l,int r,int index)//初始化
{
int mid;
tree[index].left =l;
tree[index].right=r;
tree[index].max =MAX;
tree[index].min =MIN;
if(l==r)
return ;
mid=(l+r)/2;
create(l,mid,index*2);//左子树
create(mid+1,r,index*2+1);//右子树
}
void insert(int l,int r,int index,int p,int d)
{
int mid=0;
if(l<=p&&p<=r)//p在此线段里
{
if(tree[index].max <d)
tree[index].max =d;
if(tree[index].min >d)
tree[index].min =d;
}
if(l==r)//操作到子节点,结束
return ;
mid=(l+r)/2;
if(mid>=p)
insert(l,mid,index*2,p,d);//对左子树更新
else
insert(mid+1,r,index*2+1,p,d);//对右子树更新
}
void research(int l,int r,int index,int a,int b)//寻找操作
{
int mid;
if(l==a&&r==b)//刚好为一个区间
{
if(tree[index].max >max)
max=tree[index].max ;
if(tree[index].min<min)
min=tree[index].min ;
return ;
}
if(l==r)//同样子节点结束
return ;
mid=(l+r)/2;
if(mid>=b)//在左半边
research(l,mid,index*2,a,b);
else if(mid<a)//在右半边
research(mid+1,r,index*2+1,a,b);
else//实现跨越的查找
{
research(l,mid,index*2,a,mid);
research(mid+1,r,index*2+1,mid+1,b);
}
}
int main()
{
int q,i,a;
scanf("%d%d",&n,&q);
create(1,n,1);
for(i=0;i<n;i++)
{
scanf("%d",&a);
insert(1,n,1,i+1,a);
}
int b;
while(q--)
{
scanf("%d%d",&a,&b);
min=MIN;max=MAX;
research(1,n,1,a,b);
printf("%d/n",max-min);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: