zoukankan      html  css  js  c++  java
  • [bzoj1012][JSOI2008]最大数maxnumber-题解[单调队列][二分]

    Description

      现在请求你维护一个数列,要求提供以下两种操作:1、 查询操作。语法:Q L 功能:查询当前数列中末尾L
    个数中的最大的数,并输出这个数的值。限制:L不超过当前数列的长度。2、 插入操作。语法:A n 功能:将n加
    上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取
    模,将所得答案插入到数列的末尾。限制:n是非负整数并且在长整范围内。注意:初始时数列是空的,没有一个
    数。

    Input

      第一行两个整数,M和D,其中M表示操作的个数(M <= 200,000),D如上文中所述,满足D在longint内。接下来
    M行,查询操作或者插入操作。

    Output

      对于每一个询问操作,输出一行。该行只有一个数,即序列中最后L个数的最大数。

    Sample Input

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

    Sample Output

    96
    93
    96

    话说在前。。请不要抄我的程序,并不是因为什么乱七八糟的理由,而是因为我写的太丑了,闲着没事干可以直接二分的东西强行差分然后写了个树状数组。。

    这个题很简单,我们构造一个数值递减的单调队列,队列中的每一个元素同时维护数值与在原数组中的下标,显然下标是递增的。
    然后在队列中二分下标,找到第一个>=n-L+1的下标,返回它的值就是我们要查找的最大数。
    丑陋的代码
      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstdlib>
      4 #include<cstring>
      5 using namespace std;//单调队列+树状数组+二分//我是个智障!
      6 struct num_que//单调队列
      7 {
      8     int dis,pos;
      9 }a[200005];
     10 int siz=0,las=0,n,D,d[200005],l=0;//树状数组
     11 inline int read()
     12 {
     13     char ch=getchar();
     14     int num_ber=0,k_si=1;
     15     while(ch>'9'||ch<'0'){if(ch=='-')k_si=-1;ch=getchar();}
     16     while(ch<='9'&&ch>='0'){num_ber*=10;num_ber+=ch-48;ch=getchar();}
     17     return num_ber*k_si;
     18 }
     19 int lowbit(int x)
     20 {
     21     return x&(-x);
     22 }
     23 void query();
     24 void insert();
     25 void updata(int,int);
     26 int check(int);
     27 int main()
     28 {
     29     char t;
     30     n=read();D=read();
     31     for(int io=1;io<=n;++io)
     32     {
     33         t=getchar();
     34         while(t!='A'&&t!='Q')t=getchar();
     35         if(t=='A')
     36         {
     37             insert();l++;
     38         }
     39         else if(t=='Q')
     40         {
     41             query();
     42         }
     43     }
     44     return 0;
     45 }
     46 void query()
     47 {
     48     int di=read(),le=1,ri=siz,mid,ans=0;
     49     di=l-di+1;
     50     while(le<=ri)
     51     {
     52         mid=(le+ri)/2;
     53         if(check(mid)>=di){ri=mid-1;ans=mid;}
     54         else{le=mid+1;}
     55     }
     56     printf("%d
    ",a[ans].dis);
     57     las=a[ans].dis;
     58 }
     59 void insert()
     60 {
     61     int si=read(),sum=1;
     62     si=(si%D+las%D)%D;
     63     if(si>a[siz].dis)
     64     {while(siz>0&&si>a[siz].dis)
     65     {
     66         updata(siz,-a[siz].pos);
     67         sum+=a[siz].pos;
     68         a[siz].dis=a[siz].pos=0;
     69         siz--;
     70     }
     71     }
     72     if(siz==0)
     73     {
     74         siz++;
     75         a[siz].dis=si;a[siz].pos+=sum;
     76         updata(siz,sum);
     77         return;
     78     }
     79     else if(si==a[siz].dis)
     80     {
     81         updata(siz,sum);a[siz].pos+=sum;
     82     }
     83     else if(si<a[siz].dis)
     84     {
     85         siz++;
     86         a[siz].dis=si;a[siz].pos+=sum;
     87         updata(siz,sum);
     88     }
     89 }
     90 void updata(int x,int y)
     91 {
     92     for(int i=x;i<=n;i+=lowbit(i))
     93     {
     94         d[i]+=y;
     95     }
     96 }
     97 int check(int x)
     98 {
     99     int tot=0;
    100     for(int i=x;i>0;i-=lowbit(i))
    101     {
    102         tot+=d[i];
    103     }
    104     return tot;
    105 }
    ugly
  • 相关阅读:
    Java实现 LeetCode 136 只出现一次的数字
    Java实现 LeetCode 136 只出现一次的数字
    Java实现 LeetCode 136 只出现一次的数字
    Java实现 LeetCode 135 分发糖果
    Java实现 LeetCode 135 分发糖果
    Java实现 LeetCode 135 分发糖果
    Java实现 LeetCode 134 加油站
    Java实现 LeetCode 134 加油站
    Java实现 LeetCode 134 加油站
    Java实现 LeetCode 133 克隆图
  • 原文地址:https://www.cnblogs.com/Zn-H/p/6414191.html
Copyright © 2011-2022 走看看