zoukankan      html  css  js  c++  java
  • 【题解】JSOI2008 最大数


    • 题目描述

      现在请求你维护一个数列,要求提供以下两种操作:

    1. 查询操作。
    • 语法:Q L

      功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值。

      限制:L不超过当前数列的长度。(L>=0)

    1. 插入操作。
    • 语法:A n

      • 功能:将n加上t,其中t是最近一次查询操作的答案(如果还未执行过查 询操作,则t=0),并将所得结果对一个固定的常数D取模,将所得答案插 入到数列的末尾。

      • 限制:n是整数(可能为负数)并且在长整范围内。

      • 注意:初始时数列是空的,没有一个数。

    • 输入输出格式

    1. 输入格式:
      第一行两个整数,M和D,其中M表示操作的个数(M <= 200,000),D如上文中所述,满足(0<D<2,000,000,000)

    接下来的M行,每行一个字符串,描述一个具体的操作。语法如上文所述。

    1. 输出格式:
      对于每一个查询操作,你应该按照顺序依次输出结果,每个结果占一行。
    • 输入输出样例
    1. 输入样例#1:

    5 100

    A 96

    Q 1

    A 97

    Q 1

    Q 2

    1. 输出样例#1:

    96

    93

    96


    • 前言:

      本蒟蒻很早以前就在做这道题了,当时是在搞线段树时搜到了这道题,第一眼看到这题我根本不觉得它与线段树有什么关系,于是就随便写了一个二分+伪单调栈,结果连样例都过不了。。。最近又搞起了线段树,先是看了一下黄学长的博客知道自己之前的单调栈错在了哪里,然后又搞了一棵线段树,结果玄学般全部MLE???为什么最近做题总会遇到玄学错误,于是学习黄学长方法,搞个数组记录l和r就过了。


    • 单调栈超级详解:

      推荐先搞懂这道题的手写队列方法:滑动窗口

      我们搞一个数组记录加的每一个数。在我看来,这个数组其实不能叫做栈,另一篇题解这里可能有点表达不太准确(个人观点),然后我们再搞一个数组,我们可以理解为将这个数组储存一个指针,这才是一个单调栈,因为它记录的元素从左到右是依次递减的。我们搞一个tail记录栈顶位置,当一个新数加进来时,我们将它与栈顶的元素做比较,如果栈顶的元素都比他小,就不断tail--,知道删去所有指针或找到一个比它更大的数,则停止操作,将tail++的地方存放这个新数的位置(指针)。大家可以想一想,它是要从后往前找最大的数,如果在后面已经有了一个比前面都大的数,那前面记录的指针都可以不要了,因为从这个数倒数所有查询的答案都是它。

      然后就是查询了,查询我们用二分查找查到我们要的位置,有人若是认真研究了我的代码会发现这个二分查找其实就是个lower_bound,返回大于等于这个数的第一个位置,所以它返回的就是我们需要的下标。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <algorithm>
    #include <cstring>
    #define ll long long 
    using namespace std;
    const int maxn=200010;
    ll sta[maxn];
    ll m,d,t=0;
    int node[maxn],len=0,tail=0;
    int binary_search(int x){
        int l=1,r=tail;
        int mid;
        while(l<=r){
           mid=(l+r)>>1;
            if(node[mid]>x)r=mid-1;
            else if(node[mid]==x)return mid;
            else l=mid+1;
        }
    }
    int main()
    {
        char opt[15];
    	freopen("bzoj_1012.in","r",stdin);
    	freopen("bzoj_1012.out","w",stdout);
        cin>>m>>d;
        while(m--){
            scanf("%s",opt); 
            if(opt[0]=='A'){
              ll x;
              scanf("%lld",&x);
              x=(x+t)%d;
              sta[++len]=x;
              while(tail&&sta[node[tail]]<=x)tail--;
              node[++tail]=len;
            }
            else{
              int l;
              scanf("%d",&l);
              if(l==0){
              	cout<<0<<endl;
              	t=0;
              	continue;
              }
              int x=binary_search(len+1-l);
              cout<<sta[node[x]]<<endl;
              t=sta[node[x]];	
            }
        }
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
    

    • 线段树做fa

      有人说线段树跑得很慢,为什么我这里跑得比单调栈还快???难道因为是黄 学长的玄学技巧??
      我也搞不懂之前的代码为何全部玄学MLE,就当这种新方法一种技巧吧。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    #define ll long long 
    using namespace std;
    const int maxn=200000;
    ll maxx[maxn<<2]; 
    int cnt=0;
    int L,R,tar;
    ll  m,d,t=0;
    int le[maxn<<2],ri[maxn<<2];
    void build(int now,int l,int r)
    {
    	le[now]=l,ri[now]=r;
    	if(l==r){
    		return ;
    	} 
    	
    	int mid=(l+r)>>1;
        build(now<<1,l,mid);
        build(now<<1|1,mid+1,r);
        return ;
    }
    ll query(int now){
    	int l=le[now],r=ri[now]; 
    	if(L<=l&&r<=R){
    		return maxx[now];
    	}
    	int mid=(l+r)>>1;
    	ll ans=0;
    	if(L<=mid)ans=max(ans,query(now<<1));
    	if(R>mid)ans=max(ans,query(now<<1|1));
        return ans;
    }
    void insert(int now,ll x)
    {
    	int l=le[now],r=ri[now];
    	if(l==r){
    		maxx[now]=x;
    		return ;
    	}
    	
    	int mid=(l+r)>>1;
    	if(tar<=mid)insert(now<<1,x);
    	if(mid<tar)insert(now<<1|1,x);
    	maxx[now]=max(maxx[now<<1],maxx[now<<1|1]);
    	return ;
    }
    int main()
    {
    	char opt[15];
    	cin>>m>>d;
    	build(1,1,m);
    	while(m--)
    	{
    		scanf("%s",opt);
    		if(opt[0]=='A'){
    			ll x;
    			scanf("%lld",&x);
    			tar=++cnt;
    			insert(1,(x+t)%d);
    		}
    		else{
    		    int l;
    			scanf("%d",&l);
    			if(l!=0)
    			{ 
    			L=cnt-l+1,R=cnt;
    			t=query(1);
    		    }
    		    else t=0;
    			cout<<t<<endl; 
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    Spring Cloud Config 配置高可用集群
    Spring Cloud Config 自动刷新所有节点 架构改造
    Spring Cloud Config 自动刷新所有节点
    Spring Boot war包&jar包对比
    Spring Cloud Config 服务端与 客户端之间的关系
    Spring Cloud Config 配置刷新
    Spring Cloud Config 配置中心 自动加解密功能 JCE方式
    SpringCloud 详解配置刷新的原理 使用jasypt自动加解密后 无法使用 springcloud 中的自动刷新/refresh功能
    IDEA Rest Client使用
    Spring Cloud Config 配置中心 自动加解密功能 jasypt方式
  • 原文地址:https://www.cnblogs.com/Rye-Catcher/p/8464922.html
Copyright © 2011-2022 走看看