bzoj1012 (Los Valley P1198) - [JSOI2008] The maximum number of maxnumber

Author : hiang

bzoj1012      Luo Gu P1198

Time Limit: 3 Sec     Memory Limit: 162 MB

Description

Now request you to maintain a number of columns, it requires the following two actions:

1, the query operation.

Syntax: QL

Function: the number of columns in the query at the end of L current maximum number of the number, and this number of output values.

Restrictions: L does not exceed the length of the current sequence.

2, the insertion operation.

Syntax: A n

Function: Add n t a, where t is the last answer to a query operation (if not already performed a query operation, t = 0), and the result of a fixed constant D taking mode, the answer is inserted into the resulting the end of the sequence.

Restrictions: n non-negative integer and long integer within the range.

Note: The number of columns is initially empty, not a number.

Input

  The first line of two integers, M and D, wherein M represents the number of operations (M <= 200,000), D as described hereinabove, satisfying D in longint. Next M rows, query or insertion.

Output

  For each query operation, the output line. The number is only one row, i.e., the maximum number in the sequence number of the last L.

Sample Input

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

Sample Output

96
93
96
 
 
Provide four kinds of ideas here:
1. Table 3. monotonic segment tree 2.ST queue disjoint-set 4 + Fenwick tree
First, the segment tree
While this question can be used tree line of thinking to do, but in fact do not even achievements since the outset and did not count the number of columns, only in the end of the addend the number of columns, and queries for several columns can be, so I only used an array to store interval maximum value.
Note: This topic is very abnormal data Luo Valley, plus the full data is negative, and L is 0, so wa numerous hair .... The following code is bzoj of AC code, the code will then be submitted Luo Valley All MLE , we need to change the char array of characters, the specific reasons unknown.
AC Code:
. 1 #include <bits / STDC ++ H.>
 2  the using  namespace STD;
 . 3  const  Long  Long INF = 2 * 1E9;
 . 4  #define LL Long Long
 . 5 LL D, Val [ 800 005 ];
 . 6  int m, ANS; // ANS is number of array elements 
. 7  char C;
 . 8  void the Add ( int p, int LL, int RR, int X, LL K)
 . 9 { // p is a subscript, ll, rr interval approximately corresponding to a p endpoint 
10      IF (LL ==rr)
11     {
12         val[p]=k;
13         return;
14     }
15     int mid=(ll+rr)>>1;
16     if(x<=mid)
17         add(p<<1,ll,mid,x,k);
18     if(x>mid)
19         add(p<<1|1,mid+1,rr,x,k);
20     val[p]=max(val[p<<1],val[p<<1|1]);
21 }
22 LL query(int p, int PL, int PR, int LL, int RR)
 23 is { // PL, PR interval corresponding to p is about endpoints, ll, rr interval queried about the endpoint 
24      LL = Maxx - INF;
 25      IF (PL > = LL && PR <= RR)
 26 is          return Val [P];
 27      int MID = (PL + PR) >> . 1 ;
 28      IF (LL <= MID)
 29          Maxx = max (Maxx, Query (P << . 1 , PL , MID, LL, RR));
 30      IF (RR> MID)
 31 is          Maxx = max (Maxx, Query (P << . 1 |. 1 , MID + . 1 , PR, LL, RR));
 32      return Maxx;
 33 is  }
 34 is  int main ()
 35  {
 36      LL n-, T = 0 ;
 37 [      Scanf ( " % D% LLD " , & m, & D);
 38 is      for ( int I = 0 ; I <m; I ++ )
 39      {
 40          Scanf ( " % * C% C% LLD " , & & n-C,); // the bzoj able to live, Los valleys to change the character array 
41 is          IF (C == ' A ' )
42         {
43             n=(n+t)%d;
44             ans++;
45             add(1,1,m,ans,n);
46         }
47         else
48         {
49             t=query(1,1,m,ans-n+1,ans);
50             printf("%lld\n",t);
51         }
52     }
53     return 0;
54 }

 

Two, ST table

ST table is an algorithm for solving the RMQ (range query most value), using the dp thought, query complexity is O (1), this code is about 0.8 seconds faster than the tree line, the code is more concise

Brief principle:

用一个数组st[i][j]来存储区间[i,i+(1<<j)-1]的最值,而该区间最值就等于[i,i+(1<<(j-1))-1]和[1<<(j-1),i+(1<<j)-1]的最大值,存储区间长度为2^j,所以预处理复杂度为O(nlogn)

查询时只需要将需查询区间[x,y]分成两部分,令k=(int)log2(y-x+1),区间[x,y]的长度就在2^k~2^(k+1)范围内,所以我们就可以将区间分成长度为2^k的两部分,即[x,x+(1<<k)-1],[y-(1<<k)+1,y],两部分可能有重合,只要保证覆盖了区间[x,y]即可

因为每次修改复杂度与预处理相同,所以不支持在线修改,但因为本题只需要在最后添加元素,所以我们可以反向建ST表(参考了大佬的思路),即st[i,j]存储[i-(1<<j)+1,i]的最值,这样每次修改时前面元素的ST表不受影响,每次修改的复杂度仅为O(logn)

AC代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define LL long long
 4 int m,ans;
 5 char c[2];
 6 LL d,st[200005][21];
 7 void add(int u,LL k)
 8 {
 9     st[u][0]=k;
10     for(int j=1;u-(1<<j)>=0;j++)
11         st[u][j]=max(st[u][j-1],st[u-(1<<(j-1))][j-1]);
12 }
13 LL ask(int l,int r)
14 {
15     int k=(log(r-l+1))/log(2);
16     return max(st[r][k],st[l+(1<<k)-1][k]);
17 }
18 int main()
19 {
20     LL n,t=0;
21     scanf("%d%lld",&m,&d);
22     for(int i=0;i<m;i++)
23     {
24         scanf("%s%lld",c,&n);
25         if(c[0]=='A')
26         {
27             n=(n+t)%d;
28             ans++;
29             add(ans,n);
30         }
31         else
32         {
33             t=ask(ans-n+1,ans);
34             printf("%lld\n",t);
35         }
36     }
37     return 0;
38 }

 

三、单调队列+并查集

本题只要求在数列末尾加数,所以很容易联想到单调队列,本代码比ST表又快了0.3秒左右

具体思路:

令队列中小于等于新元素的数全部出队,再另新元素入队,这样可以得到一个递减队列,队列中的每个数就代表数列中从该元素开始到末尾的最大值

假如要查询第x个元素到末尾的最大值,那么我们只需要从第x个元素开始,找第一个在单调队列里出现的数,该数即为该区间最大值

但如果要从x开始一个个遍历的话复杂度过高,这里就可以用并查集,将第i个元素与它后面第一个比它大的元素放到一个集合里,这样查询x时就可以直接找到后面第一个比它大的元素,并一直往后找,直到找不到更大的数为止

AC代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define MAXN 200005
 4 int m,d,ans,s;//ans为数列元素个数,s为队列元素个数
 5 int a[MAXN];//原始数列
 6 int q[MAXN];//单调队列,存储下标
 7 int pre[MAXN];//并查集,存储数列中i之后第一个比a[i]大的数的下标
 8 char c[2];
 9 int ufind(int x)
10 {
11     while(x!=pre[x])
12         x=pre[x];
13     return x;
14 }
15 int main()
16 {
17     int n,t=0;
18     scanf("%d%d",&m,&d);
19     for(int i=0;i<m;i++)
20     {
21         scanf("%s%d",c,&n);
22         if(c[0]=='A')
23         {
24             a[++ans]=(n+t)%d;
25             pre[ans]=ans;//每个数的上级初始化为自己
26             while(s>0&&a[q[s]]<a[ans])
27             {
28                 pre[q[s]]=ans;
29 s--; 30 }//将队列中小于新元素的上级改为新元素,并出队 31 q[++s]=ans;//新元素入队 32 } 33 else 34 { 35 t=a[ufind(ans-n+1)]; 36 printf("%d\n",t); 37 } 38 } 39 return 0; 40 }

 

 四、树状数组

树状数组可用于单点修改,区间查询,本题符合该特点

需要注意的是,查询区间是从L到末尾,所以要反向建树状数组,即更新时从后往前更新,查询时从前往后查询

AC代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int m,ans,d;
 4 char c[2];
 5 int s[200005];//树状数组
 6 int lowbit(int x)
 7 {
 8     return x&(-x);
 9 }
10 void update(int x,int k)
11 {
12     for(int i=x;i>0;i-=lowbit(i))
13         s[i]=max(s[i],k);
14 }
15 int query(int x)
16 {
17     int maxx=-1e9;
18     for(int i=x;i<=ans;i+=lowbit(i))
19         maxx=max(maxx,s[i]);
20     return maxx;
21 }
22 int main()
23 {
24     int n,t=0;
25     scanf("%d%d",&m,&d);
26     for(int i=0;i<m;i++)
27     {
28         scanf("%s%d",c,&n);
29         if(c[0]=='A')
30         {
31             n=(n+t)%d;
32             ans++;
33             update(ans,n);
34         }
35         else
36         {
37             t=query(ans-n+1);
38             printf("%d\n",t);
39         }
40     }
41     return 0;
42 }

 

 

Guess you like

Origin www.cnblogs.com/CSGOBESTGAMEEVER/p/10989177.html