FZU1862(线段树 或者 DP)

本文介绍了一种在给定区间内查询最大值的算法问题,提供了两种解决方案:一种使用线段树实现,另一种通过动态规划解决。适用于处理大量查询请求,并提供高效的查询速度。
Problem 1862 QueryProblem

Accept: 100    Submit: 249
Time Limit: 2000 mSec    Memory Limit : 32768 KB

Problem Description


There are N numbers (non-negative integers) in a circle. Now your task is quite simple, just tell me the largest number between L and R.
The Figure 1 is a sample of five integers in a circle. (marked with their index, but not their exact value.)
Figure 1.

The Figure 2,3 show how we count the number.

Figure 2.


Figure 3.

Input

There are no more than 10 test cases;

For each case, the first line contains only one integer N, indicates the size of the circle.

The following one line contains N non-negative integers where Mi indicates the i-th integers whose index is i. (1 <= N <= 1000, 1 <= i <= N, 0 <= Mi <= 10^9)

Then one line contains Q indicates the number of querys. (1 <= Q <= 10^5)

Then the next Q lines, each line contains only two integers indicate L and R (1 <= L,R <= N)

Output

For each case, please output “Case #index:” in a single line, here index is the case index starts from one.

For each query just output a single line indicates the largest number between L and R.

Output a blank line after each case.

Sample Input

2 3 8 3 1 1 1 2 2 1 1 9 1 1 1

Sample Output

Case #1: 3 8 8 Case #2: 9

Hint

Huge Input, please “scanf” to avoid time limit exceed.

题意:在给定的区间中查询最大的数。当L>R时,R =R +n 来改变R这也是2*n的原因;

方法1:线段树

收获:函数中的num指的是线段树上的编号,而当le == ri时,le 或 ri指的是最低层的编号。

#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <ctime>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <queue>
#include <list>
#include <vector>
#include <map>
#include <set>
using namespace std;

const int INF=0x3f3f3f3f;
const double eps=1e-10;
const double PI=acos(-1.0);
#define maxn 8006
int tre[maxn];
int a[maxn/4];
int n;
void build(int num, int le, int ri)
{
    if(le == ri)
    {
        if(le > n)
            tre[num] = a[le-n];//函数中的num指的是线段树上的编号,而当le == ri时,le 或 ri指的是最低层的编号。
        else
            tre[num] = a[le];
        return;
    }
    int mid = (le + ri)/2;
    build(num*2, le, mid);
    build(num*2+1, mid+1, ri);
    tre[num] = max(tre[num*2], tre[num*2+1]);
}
int query(int num,int le,int ri,int x,int y)
{
    if(x<=le&&y>=ri)
        return tre[num];
    int mid=(le+ri)/2;
    int ans=0;
    if(x<=mid)
        ans=max(ans,query(num*2,le,mid,x,y)); //先查询左边
    if(y>mid)
        ans=max(ans,query(num*2+1,mid+1,ri,x,y)); //再查询右边
    return ans;
}
int main()
{
    int cas = 1;
    while(~scanf("%d", &n))
    {
        for(int i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        build(1, 1, 2*n);
        int m;
        scanf("%d", &m);
        int a, b;
        printf("Case #%d:\n", cas++);
        for(int j = 0; j < m; j++)
        {
            scanf("%d%d", &a, &b);
            if(b < a)
                b = b + n;
            printf("%d\n", query(1, 1, 2*n, a, b));
        }
        puts("");
    }
}

方法2:DP

收获:对dp有了更多的了解。

dp[i][j]指的是i到j这个区间内保存的最大值。

#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <ctime>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <queue>
#include <list>
#include <vector>
#include <map>
#include <set>
#define C 0.57721566490153286060651209
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1


using namespace std;

typedef long long LL;
const int INF=0x3f3f3f3f;
const double eps=1e-10;
const double PI=acos(-1.0);

const int maxn=1000009;
int dp[2020][2020];
int a[2020];
int main()
{
    int n, b;
    int sum=0;
    while(~scanf("%d", &n))
    {
        for(int i = 1; i <= n; i++)
        {
            scanf("%d", &b);
            a[i]=a[i+n]=b;
        }
        for(int i = 1; i <=2*n; i++)
        {
             dp[i][i]=a[i];
            for(int j=i+1;j<=2*n;j++)
            {
                if(a[j]>dp[i][j-1])
                    dp[i][j]=a[j];
                else
                    dp[i][j]=dp[i][j-1];
            }
        }
        int m;
        scanf("%d", &m);
        int L, R;
        printf("Case #%d:\n",++sum);
        for(int i=1;i<=m;i++)
        {
            int q,w;
            scanf("%d%d",&q,&w);
            if(w<q)
                w=w+n;
            printf("%d\n",dp[q][w]);
        }
        puts("");
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/ZP-Better/p/4722400.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值