[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
A 96
Q 1
A 97
Q 1
Q 2
Sample Output
96
93
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\n",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 }