您的位置:首页 > 其它

POJ3264 RMQ问题 裸 线段树 OR ST算法

2016-05-05 00:15 435 查看
0)解决RMQ问题。此处用线段树或ST算法。

线段树O(logn)的复杂度一般可以AC,ST算法是O(nlogn)预处理和O(1)的查询速度,一般情况下线段树快一些但如果查询量非常大,ST算法优于线段树。

1)注意,NodeNum一般开3倍或4倍。

如果对输出格式要求不是很多,那么用cout比printf快哦。

线段树,O(logn)复杂度,2000ms(把最后cout改为printf就会3000ms多哦)

#include <iostream>
#include <stdio.h>
#include <algorithm>

using namespace std;
const int INF=0x3f3f3f3f;
const int NodeNum=200005*3;
const int queNum=200010;
int a[NodeNum];
int nmin;
int nmax;
struct Node{
int l;
int r;
int minn;
int maxx;
}node[NodeNum];
void Build(int id,int l,int r){
node[id].l=l;
node[id].r=r;
if(l==r){
node[id].maxx=a[l];
node[id].minn=a[l];
return ;
}
int mid=(l+r)>>1;
Build(id<<1,l,mid);
Build((id<<1)+1,mid+1,r);
node[id].maxx=max(node[id<<1].maxx,node[(id<<1)+1].maxx);//(id<<1)+1可以换成id<<1|1,意思是如果id<<1是偶数那么就+1,否则就不变,因为id<<1所以一定是偶数
node[id].minn=min(node[id<<1].minn,node[(id<<1)+1].minn);//因为优先级的原因,所以(id<<1)+1中的括号是有必要的
}
void Query(int id,int l,int r){
if(node[id].maxx<=nmax&&nmin<=node[id].minn){
return ;
}
if(node[id].l==l&&r==node[id].r){
nmin=min(nmin,node[id].minn);
nmax=max(nmax,node[id].maxx);
return;
}
int mid=(node[id].l+node[id].r)>>1;
if(r<=mid){
Query(id<<1,l,r);
}
else if(mid+1<=l){
Query((id<<1)+1,l,r);
}
else {
Query(id<<1,l,mid);
Query((id<<1)+1,mid+1,r);
}
}
int main(){
int n,q;
while(~scanf("%d %d",&n,&q)){
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
Build(1,1,n);
for(int i=1;i<=q;i++){
int l,r;
nmin=INF;
nmax=-INF;
scanf("%d %d",&l,&r);
Query(1,l,r);
cout<<nmax-nmin<<endl;
//printf("%d\n",nmax-nmin);
}
}
return 0;
}


ST算法(动态规划),O(nlogn)预处理和O(1)的查询,3400ms(把printf改为cout3200ms,这个差距不大,但这个现象却恰恰诠释了ST算法是O(1)的查询速度,所以对于查询时输出用cout还是printf的优化效果不如O(logn)的线段树对查询输出进行优化的效果更明显!)

//RMQ ---RMQ简介 :http://blog.csdn.net/niushuai666/article/details/6624672
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <math.h>

using namespace std;
const int maxn=50010;
//int cows[maxn];
int heigh[maxn][20];
int low[maxn][20];
void Rmq(int num){
//预处理,递推并记忆,利用二进制,存储每个数起(包括它本身),往后2^0 2^1 2^2......2^k个数来覆盖所有区间。
//第i个数开始,往后j个数,把这部分平分成两半处理,直到每个数都是往后2^0个(本身),也就是初始化的状态。
for(int j=1;j<20;j++){
for(int i=1;i<=num;i++){
if(i+(1<<j)-1<=num){
heigh[i][j]=max(heigh[i][j-1],heigh[i+(1<<(j-1))][j-1]);
low[i][j]=min(low[i][j-1],low[i+(1<<(j-1))][j-1]);
}
}
}
}
int main()
{
int n,q;
cin>>n>>q;
//先进行初始化,将所有一个数的(每个数本身)进行赋值。
for(int i=1;i<=n;i++){
scanf("%d",&heigh[i][0]);
low[i][0]=heigh[i][0];
}
Rmq(n);
int star,endd;
for(int l=1;l<=q;l++){
scanf("%d%d",&star,&endd);
//查询的区间,可以分成两个有交集的区间,分别求最大或最小,然后再比较一次得到最值,因此可以覆盖所有区间!
if(star>endd){
swap(star,endd);
}
int k=(int)(log(endd-star+1.0)/log(2.0));//+1.0变成floor
printf("%d\n",max(heigh[star][k],heigh[endd-(1<<k)+1][k])-min(low[star][k],low[endd-(1<<k)+1][k]));//int res=max(heigh[star][k],heigh[endd-(1<<k)+1][k])-min(low[star][k],low[endd-(1<<k)+1][k]);	cout<<res<<endl;
}
}


2)

Description

For the daily milking, Farmer John's N cows (1 ≤ N ≤ 50,000) always line up in the same order. One day Farmer John decides to organize a game of Ultimate Frisbee with some of the cows. To keep things simple, he will take a contiguous range
of cows from the milking lineup to play the game. However, for all the cows to have fun they should not differ too much in height.

Farmer John has made a list of Q (1 ≤ Q ≤ 200,000) potential groups of cows and their heights (1 ≤height ≤ 1,000,000). For each group, he wants your help to determine the difference in height between the shortest and the tallest
cow in the group.

Input

Line 1: Two space-separated integers, N andQ.

Lines 2.. N+1: Line i+1 contains a single integer that is the height of cowi

Lines N+2.. N+ Q+1: Two integers A and B (1 ≤A ≤B ≤N), representing the range of cows fromA toB inclusive.

Output

Lines 1.. Q: Each line contains a single integer that is a response to a reply and indicates the difference in height between the tallest and shortest cow in the range.

Sample Input

6 3
1
7
3
4
2
5
1 5
4 6
2 2


Sample Output

6
3
0
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: