洛谷 P1198 [JSOI2008]最大数 单调栈+(二分或者并查集)或者 ST表 或者 线段树 或者树状数组

                                      P1198 [JSOI2008]最大数

 

题目描述

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

1、 查询操作。

语法:Q L

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

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

2、 插入操作。

语法:A n

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

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

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

输入输出格式

输入格式:

 

第一行两个整数, MMM 和 DDD ,其中 MMM 表示操作的个数 (M≤200,000)(M \le 200,000)(M≤200,000) , DDD 如上文中所述,满足 (0

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

 

输出格式:

 

对于每一个查询操作,你应该按照顺序依次输出结果,每个结果占一行。

 

输入输出样例

输入样例#1: 复制

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

输出样例#1: 复制

96
93
96

 

单调栈 + 二分查找做法

#include 
using namespace std;
typedef long long LL;
typedef pair P;
const int maxn = 2e5 + 1000;

int cnt[maxn];
int a[maxn];
int m;
int d;
int tail;

int main()
{
   scanf("%d%d",&m,&d);
     int t = 0;
   int num = 0;
   tail = -1;
     while(m--)
     {
         char op;
         cin >> op;
         if(op == 'A')
         {
             int n;
             scanf("%d",&n);
             n = (n+t)%d;
             while(tail >= 0 && a[cnt[tail]] < n) tail--;
       a[++num] = n;
             cnt[++tail] = num;
         }
         else {
             int L;
             scanf("%d",&L);
       //printf("0\n");
             L = (num-L+1);
       int idx = lower_bound(cnt,cnt+tail+1,L) - cnt;
       printf("%d\n",a[cnt[idx]]);
       t = a[cnt[idx]];
         }
     }
     return 0;
}

 

单调栈 + 并查集做法

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
const int maxn = 2e5  + 100;
const int maxm = 4e5 + 100;
const int INF = 0x3f3f3f3f;
//const int mod = 1e9 + 7;
typedef pair P;
typedef long long LL;
const LL mod = 1e9 + 7;

#define PI 3.1415926
#define sc(x)  scanf("%d",&x)
#define pf(x)  printf("%d",x)
#define pfn(x) printf("%d\n",x)
#define pfln(x) printf("%I64d\n",x)
#define pfs(x) printf("%d ",x)
#define rep(i,a,n) for(int i = a; i < n; i++)
#define per(i,a,n) for(int i = n-1; i >= a; i--)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb(x)  push_back(x);


stack s;
int f[maxn];
int a[maxn];
void init()
{
  rep(i,0,maxn) f[i] = i;
}

int find(int x)
{
  return f[x] == x ? x : f[x] = find(f[x]);
}

void unit(int x, int y)
{
  f[find(y)] = x;
}

int main()
{
   int t = 0,m,mod,num = 0;
   scanf("%d%d",&m,&mod);
   init();
   while(m--)
   {
     char c;
     cin >> c;
     if(c == 'A')
     {
       sc(a[++num]);
       a[num] = (a[num]+t)%mod;
       while(!s.empty() && a[s.top()] <= a[num]) {unit(num,s.top()), s.pop();}
       s.push(num);
     }
     else
     {
       int L;
       sc(L);
       pfn(t = a[find(num-L+1)]);
     }
   }
   return 0;
}

 

ST表做法,反向建ST表,f[i][j] 表示 a[i-(1< a[i] 的最大值 ,因为前面的值不会改变,所以就相当于一个不断建表的过程。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
const int maxn = 2e5  + 100;
const int maxm = 4e5 + 100;
const int INF = 0x3f3f3f3f;
//const int mod = 1e9 + 7;
typedef pair P;
typedef long long LL;
const LL mod = 1e9 + 7;

#define PI 3.1415926
#define sc(x)  scanf("%d",&x)
#define pf(x)  printf("%d",x)
#define pfn(x) printf("%d\n",x)
#define pfln(x) printf("%I64d\n",x)
#define pfs(x) printf("%d ",x)
#define rep(i,a,n) for(int i = a; i < n; i++)
#define per(i,a,n) for(int i = n-1; i >= a; i--)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb(x)  push_back(x);


int f[maxn][20];
int a[maxn];
void change(int u)
{
  f[u][0] = a[u];
  for(int i = 1; u-(1<= 0; ++i)  f[u][i] = max(f[u][i-1],f[u- (1<<(i-1))][i-1]);
}

int find(int l, int r)
{
  int k = log2(r-l+1);
  return max(f[r][k],f[l+(1<> c;
     if(c == 'A')
     {
       sc(a[++num]);
       a[num] = (a[num]+t)%mod;
       change(num);
     }
     else
     {
       int L;
       sc(L);
       pfn(t = find(num-L+1,num));
     }
   }
   return 0;
}

 

反向树状数组

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
const int maxn = 2e5  + 100;
const int maxm = 4e5 + 100;
const int INF = 0x3f3f3f3f;
//const int mod = 1e9 + 7;
typedef pair P;
typedef long long LL;
const LL mod = 1e9 + 7;

#define PI 3.1415926
#define sc(x)  scanf("%d",&x)
#define pf(x)  printf("%d",x)
#define pfn(x) printf("%d\n",x)
#define pfln(x) printf("%I64d\n",x)
#define pfs(x) printf("%d ",x)
#define rep(i,a,n) for(int i = a; i < n; i++)
#define per(i,a,n) for(int i = n-1; i >= a; i--)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb(x)  push_back(x);


int a[maxn];
int c[maxn];

int main()
{
   int t = 0,m,mod,num = 0;
   scanf("%d%d",&m,&mod);
   while(m--)
   {
     char op;
     cin >> op;
     if(op == 'A')
     {
       sc(a[++num]);
       a[num] = (a[num]+t)%mod;
       for(int x = num; x; x -= x&-x) c[x] = max(c[x],a[num]);
     }
     else
     {
       int L;
       sc(L);
       int res = -1*INF;
       for(int x = num-L+1; x <= num; x += x&-x)  res = max(res,c[x]);
       pfn(t = res);
     }
   }
   return 0;
}

 

线段树 单点更新+区间求最值

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
const int maxn = 2e5  + 100;
const int maxm = 8e5 + 100;
const int INF = 0x3f3f3f3f;
//const int mod = 1e9 + 7;
typedef pair P;
typedef long long LL;
const LL mod = 1e9 + 7;

#define PI 3.1415926
#define sc(x)  scanf("%d",&x)
#define pf(x)  printf("%d",x)
#define pfn(x) printf("%d\n",x)
#define pfln(x) printf("%I64d\n",x)
#define pfs(x) printf("%d ",x)
#define rep(i,a,n) for(int i = a; i < n; i++)
#define per(i,a,n) for(int i = n-1; i >= a; i--)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb(x)  push_back(x);

int mx[maxm];
void update(int s, int k, int o, int l, int r)
{
  if(l == r) {mx[o] = k; return; }
  int mid = l + (r-l)/2;
  if(mid >=s) update(s,k,o<<1,l,mid);
  if(mid < s) update(s,k,o<<1|1,mid+1,r);
  mx[o] = max(mx[o<<1],mx[o<<1|1]);
}

int query(int x, int y, int o, int l, int r)
{
  //cout << x << " " << y << " " << o << " " << l << " " << r << endl;
  if (y < l || x > r) return -1*INF;
  int mid = l + (r-l)/2;
  if(x <= l && y >= r) return mx[o];
  return max(query(x,y,o<<1,l,mid),query(x,y,o<<1|1,mid+1,r));
}

int main()
{
    int m,mod,num = 0,t = 0;
    scanf("%d%d",&m,&mod);
    rep(i,0,m)
    {
      char op;
      cin >> op;
      if(op == 'A')  {int n; sc(n); update(++num,(n+t)%mod,1,1,m);}
      else {int L; sc(L); t = query(num-L+1,num,1,1,m); pfn(t);}
    }
    return 0;
}

 

 

你可能感兴趣的:(数据结构)