题目描述
有一座延绵不断、跌宕起伏的山,最低处海拔为0米,最高处海拔不超过8848米。从这座山的一端走到另一端的过程中,每走 1 米海拔高度就升高 1 米或者降低 1 米。有 Q 个登山队计划在这座山的不同区段登山,当他们攀到各自区段内的最高峰时,就会插上他们的队旗。请你写一个程序找出他们插旗的高度。
输入
第一行为 N(N≤10^6 ),表示山两端的跨度。接下来 N+1 行,每行一个非负整数Hi (i=0..N),表示该位置的海拔高度(单位:米),其中 H0=Hn=0。然后是一个正整数Q(Q≤7000),表示登山队的数量。紧跟的Q行,每行两个数Ai和Bi,表示第 i 个登山队攀爬的区段[Ai,Bi],其中0≤Ai≤Bi≤N。
10
0
1
2
3
2
3
4
3
2
1
0
5
0 10
2 4
3 7
7 9
8 8
4
3
4
3
2
这就是个裸的RMQ 用线段树也可以,但是这不是重点。。。
先上代码
1 . 正常线段树
#include
#include
#include
#include
#include
using namespace std;
int a[1000000]={0};
int n,k;
struct treenode {
int left,middle,right;
int maxx,minn;
treenode *lchild;
treenode *rchild;
};
treenode* build_tree(int l,int r)
{
treenode *node=new treenode();
int mid=(l+r)>>1;
node->middle=mid;
node->left=l;
node->right=r;
node->lchild=NULL;
node->rchild=NULL;
if(r-l==1)
{
node->maxx=a[l];node->minn=a[l];return node;
}
node->lchild=build_tree(l,mid);
node->rchild=build_tree(mid,r);
node->maxx=max(node->lchild->maxx,node->rchild->maxx);
node->minn=min(node->lchild->minn,node->rchild->minn);
return node;
}
int query(treenode *node,int l,int r)
{
if((l==node->left)&&(r==node->right))
return node->maxx;
if(l>=node->middle)
return query(node->rchild,l,r);
if(r<=node->middle)
return query(node->lchild,l,r);
else
return max(query(node->lchild,l,node->middle),query(node->rchild,node->middle,r));
}
int main()
{
int n,m;
scanf("%d",&n);
for(int i=0;i<=n;i++)
{
scanf("%d",&a[i]);
}
treenode *root=build_tree(0,n+1);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
int temp=query(root,x,y+1);
printf("%d\n",temp);
}
return 0;
}
2 . ZKW线段树
#include
#include
#include
using namespace std;
const int N=100005;
int M;
int T[4*N];
void PushUP(int rt)
{
T[rt]=max(T[rt<<1],T[rt<<1|1]);
}
void Build(int n)
{
for(M=1; M<=n+1; M<<=1);
for(int i=M+1; i<=M+n+1; i++)
scanf("%d",&T[i]);
for(int i=M-1; i>0; i--)
PushUP(i);
}
void Add(int n,int v)
{
for(T[n+=M]=v,n>>=1; n; n>>=1)
PushUP(n);
}
int Query(int s,int t)
{
int ans=0;
for(s=s+M-1,t=t+M+1; s^t^1; s>>=1,t>>=1)
{
if(~s&1) ans=max(T[s^1],ans);
if(t&1) ans=max(T[t^1],ans);
}
return ans;
}
int main()
{
freopen("climb.in","r",stdin);
freopen("climb.out","w",stdout);
char str[15];
int n,t,a,b,k=1,m;
scanf("%d",&n);
Build(n);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
printf("%d\n",Query(a+1,b+1));
}
return 0;
}
3 . RMQ
#include
#include
#include
using namespace std;
#define max(a,b) a>b?a:b
#define min(a,b) a>b?b:a
#define MAX 1000001
int a[MAX], dpmax[MAX][20];
void RMQ(int N)
{
int i, j;
for(i=1; i<=N; i++)
{
dpmax[i][0] = a[i];
}
for(j=1; j<=log(N+1.0)/log(2.0); j++)
for(i=1; i<=N-(1<1; i++)
dpmax[i][j] = max(dpmax[i][j-1], dpmax[i+(1<<(j-1))][j-1]);
}
int main()
{
int N, Q, i, j, k, aa, bb;
scanf("%d", &N);
for(i=1; i<=N+1; i++)
scanf("%d", &a[i]);
RMQ(N+1);
scanf("%d",&Q);
while(Q--)
{
scanf("%d%d", &i, &j);i++,j++;
k = log(j - i + 1.0) / log(2.0);
aa = max(dpmax[i][k], dpmax[j-(1<1][k]);
printf("%d\n", aa);
}
return 0;
}
RMQ超时了两个点,估计是写挂了,代码先挂上,不要粘去水题哦、
重点是什么来着???
哦对,这题普通线段树写最后两个点1.2秒左右,然而我大重口味(ZKW)线段树只用0.1秒。。秒出哦。。。。。代码还够短哈哈