• [JSOI2008] [洛谷P1198] 最大数|线段树80'|单调栈100'


     题目描述 Description
    现在请求你维护一个数列,要求提供以下两种操作:
    1、 查询操作。
    语法:Q L
    功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值。
    限制:L不超过当前数列的长度。
    2、 插入操作。
    语法:A n
    功能:将n加上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取模,将所得答案插入到数列的末尾。
    限制:n是整数(可能为负数)并且在长整范围内。
    注意:初始时数列是空的,没有一个数。
     输入输出格式 Input/output
    输入格式:
    第一行两个整数,M和D,其中M表示操作的个数(M <= 200,000),D如上文中所述,满足(0<D<2,000,000,000)
    接下来的M行,每行一个字符串,描述一个具体的操作。语法如上文所述。
    输出格式:
    对于每一个查询操作,你应该按照顺序依次输出结果,每个结果占一行。
     输入输出样例 Sample input/output
    样例测试点#1
    输入样例:

    5 100
    A 96
    Q 1
    A 97
    Q 1
    Q 2

    输出样例:

    96
    93
    96

    分析:单调栈,AC。

    由于本题求的是末尾L个数中的最大值,可以得出若num[i]<num[i+1],则num[i]是永远不会被取到的。所以维护一个单调递减的栈即可。

    代码简单!查找的时候可以用STL中的lower_bound (#include<vector>)。简单高效!

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstdlib>
    #include<cstring>
    #include<vector>
    using namespace std;
    int n,d,t,y;
    int top,len,a[200001],num[200001];
    int main()
    {
        int x;
        char ch[1];
        scanf("%d%d",&n,&d);
        while(n--)
        {
                  scanf("%s%d",ch,&x); 
                  if(ch[0]=='A')
                  {
                          x=(x+t)%d;
                          num[++len]=x;
                          while(top&&num[a[top]]<=x)top--;
                          a[++top]=len;      
                  }
                  else
                  {
                          y=lower_bound(a+1,a+top+1,len-x+1)-a;
                          t=num[a[y]];
                          printf("%d
    ",num[a[y]]);
                  }
        }
        return 0;
    }

    分析:线段树,80分。

    我想的线段树的写法是先存入各操作,建树后离线操作。每次询问后修改相关节点(具体见代码),最后两点未过,不知何因。

    #include<iostream>  
    #include<cstdlib>  
    #include<cstdio>  
    #include<cstring>  
    using namespace std;  
    int m,D,sum,t,x,maxn,sum1,sum2,ss,tt,num1[200001],num2[200001][2],sq[800001];  
    char c;  
    void build_tree(int s,int t,int now)  
    {  
         int mid;  
         if (s==t)   
         {  
                   sq[now]=num1[s];  
                   return;  
         }  
         mid=(s+t)/2;  
         build_tree(s,mid,now*2);  
         build_tree(mid+1,t,now*2+1);  
         sq[now]=max(sq[now*2],sq[now*2+1]);     
    }      
    int find_tree(int s,int t,int now)  
    {  
        int mid,ans;  
        if (s>=ss&&t<=tt) return sq[now];  
        mid=(s+t)/2;  
        if (ss<=mid) ans=find_tree(s,mid,now*2); else ans=-1;  
        if (tt>mid) ans=max(ans,find_tree(mid+1,t,now*2+1));  
        return ans;  
    }  
    void fix_tree(int s,int t,int now)  
    {  
         int mid;  
         if (s==ss&&s==t)   
         {  
                   sq[now]=tt;  
                   return;  
         }  
         mid=(s+t)/2;  
         if (ss<=mid)  
         {  
                    fix_tree(s,mid,now*2);  
                    sq[now]=max(sq[now*2],sq[now*2+1]);  
         }  
         if (ss>mid)   
         {  
                     fix_tree(mid+1,t,now*2+1);  
                     sq[now]=max(sq[now*2],sq[now*2+1]);  
         }  
    }   
    int main()  
    {  
        scanf("%d%d",&m,&D);  
        getchar();  
        t=0;  
        sum=0;  
        for (int i=1;i<=m;i++)  
        {  
            c=getchar();  
            scanf("%d",&x);  
            if (c=='A')  
            {  
                       sum1++;  
                       num1[sum1]=x;  
            }  
            if (c=='Q')  
            {  
                       sum2++;  
                       num2[sum2][1]=sum1-x+1;  
                       num2[sum2][2]=sum1;  
            }  
            getchar();  
        }  
        build_tree(1,sum1,1);  
        for (int i=1;i<=sum2;i++)  
        {  
            ss=num2[i][1];  
            tt=num2[i][2];  
            t=find_tree(1,sum1,1);  
            printf("%d
    ",t);  
            if (num2[i][2]==sum1) continue;  
            for (int j=num2[i][2]+1;j<=num2[i+1][2];j++)  
            {  
                ss=j;  
                tt=(num1[j]%D+t%D)%D;  
                fix_tree(1,sum1,1);  
            }  
        }  
        return 0;  
    }  

    测试点 #1通过该测试点。 得分10,耗时187ms,内存4317kB。
    测试点 #2通过该测试点。 得分10,耗时0ms,内存2060kB。
    测试点 #3通过该测试点。 得分10,耗时0ms,内存2068kB。
    测试点 #4通过该测试点。 得分10,耗时15ms,内存2306kB。
    测试点 #5通过该测试点。 得分10,耗时93ms,内存3215kB。
    测试点 #6通过该测试点。 得分10,耗时109ms,内存3891kB。
    测试点 #7通过该测试点。 得分10,耗时202ms,内存4313kB。
    测试点 #8通过该测试点。 得分10,耗时234ms,内存3948kB。
    测试点 #9错误的答案。 得分0,耗时187ms,内存4313kB。

    • 该行正确答案长度:10 你的答案长度:2
    • 你是在整个测试点输出的 0% 地方开始出错的。
    • 这一行你是在第 2 个字符开始与标准输出不同的。

    测试点 #10错误的答案。 得分0,耗时187ms,内存4317kB。

    • 该行正确答案长度:10 你的答案长度:2
    • 你是在整个测试点输出的 0% 地方开始出错的。
    • 这一行你是在第 2 个字符开始与标准输出不同的。
  • 相关阅读:
    KafkaOffsetMonitor
    锋利的KATANA
    用grunt搭建自动化的web前端开发环境
    网上书店订单功能的实现
    作用域和控制器
    使用CLK.AspNet.Identity提供以角色为基础的访问控制(RBAC)
    ABP日志管理
    .NET开源项目
    服务总线
    Message解析流程(转)
  • 原文地址:https://www.cnblogs.com/ws-fqk/p/4392383.html
Copyright © 2020-2023  润新知