【线段树】登山climb

来源:互联网 发布:读懂中国经济数据 编辑:程序博客网 时间:2024/05/16 07:50
  • 题目描述
    有一座延绵不断、跌宕起伏的山,最低处海拔为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。

  • 输出
    共Q行,每行一个整数,表示第 i 个登山队攀爬区段中最高点的高度。
  • 样例输入

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 <iostream> #include <cstdio> #include <vector> #include <climits> #include <cstdlib> 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 <iostream>#include <string.h>#include <stdio.h>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<cmath>#include<iostream>#include<cstdio>using namespace std;#define max(a,b) a>b?a:b#define min(a,b) a>b?b:a#define MAX 1000001int 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<<j)+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<<k)+1][k]);        printf("%d\n", aa);    }    return 0;}

RMQ超时了两个点,估计是写挂了,代码先挂上,不要粘去水题哦、

重点是什么来着???
哦对,这题普通线段树写最后两个点1.2秒左右,然而我大重口味(ZKW)线段树只用0.1秒。。秒出哦。。。。。代码还够短哈哈

0 0
原创粉丝点击