zoukankan      html  css  js  c++  java
  • 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:
    ", cas++);
            for(int j = 0; j < m; j++)
            {
                scanf("%d%d", &a, &b);
                if(b < a)
                    b = b + n;
                printf("%d
    ", 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:
    ",++sum);
            for(int i=1;i<=m;i++)
            {
                int q,w;
                scanf("%d%d",&q,&w);
                if(w<q)
                    w=w+n;
                printf("%d
    ",dp[q][w]);
            }
            puts("");
        }
        return 0;
    }
  • 相关阅读:
    【ZJOI 2008】 生日聚会
    BZOJ2135 刷题计划(贪心+二分)
    BZOJ2124 等差子序列(树状数组+哈希)
    BZOJ2282 SDOI2011消防/NOIP2007树网的核(二分答案+树形dp)
    BZOJ1304 CQOI2009叶子的染色(树形dp)
    BZOJ1283 序列(费用流)
    BZOJ1266 AHOI2006上学路线(最短路+最小割)
    BZOJ1041 HAOI2008圆上的整点(数论)
    BZOJ3505 CQOI2014数三角形(组合数学)
    BZOJ5206 JSOI2017原力(三元环计数)
  • 原文地址:https://www.cnblogs.com/ZP-Better/p/4722400.html
Copyright © 2011-2022 走看看