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<D<2,000,000,000)(0<D<2,000,000,000)(0<D<2,000,000,000)
接下来的 MMM 行,每行一个字符串,描述一个具体的操作。语法如上文所述。
输出格式:
对于每一个查询操作,你应该按照顺序依次输出结果,每个结果占一行。
输入输出样例
输入样例#1: 复制
5 100
A 96
Q 1
A 97
Q 1
Q 2
输出样例#1: 复制
96
93
96
单调栈 + 二分查找做法
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,LL> 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 <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;
const int maxn = 2e5 + 100;
const int maxm = 4e5 + 100;
const int INF = 0x3f3f3f3f;
//const int mod = 1e9 + 7;
typedef pair<int,int> 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<int> 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<<j)+1] -> a[i] 的最大值 ,因为前面的值不会改变,所以就相当于一个不断建表的过程。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;
const int maxn = 2e5 + 100;
const int maxm = 4e5 + 100;
const int INF = 0x3f3f3f3f;
//const int mod = 1e9 + 7;
typedef pair<int,int> 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<<i)>= 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<<k)-1][k]);
}
int main()
{
int t = 0,m,mod,num = 0;
scanf("%d%d",&m,&mod);
while(m--)
{
char c;
cin >> 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 <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;
const int maxn = 2e5 + 100;
const int maxm = 4e5 + 100;
const int INF = 0x3f3f3f3f;
//const int mod = 1e9 + 7;
typedef pair<int,int> 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 <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;
const int maxn = 2e5 + 100;
const int maxm = 8e5 + 100;
const int INF = 0x3f3f3f3f;
//const int mod = 1e9 + 7;
typedef pair<int,int> 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;
}