题目描述
小Z最近在研究数列,他需要知道在他所研究的数列中,最大的数是多少(Max),最小的数是多少(Min),最大的数的最小的数次幂是多少(Max^Min),所有数的乘积是多少。要知道,这样的问题是肯定难不倒小Z的。但是,最近小Z突发奇想,想要研究下这个数列的更深层的性质,所以他决定不断的从这个数列中删去一些数,每次删除后都研究下当前数列。由于数列项数很大,这给小Z带来了很大的麻烦,于是小Z请你帮他写一个程序,来完成下列操作。
D x:表示从数列中删除x,保证数列中一定会有x。
B:输出当前数列中的最大数,保证数列不为空。
S:输出当前数列中的最小数,保证数列不为空。
M:输出Max^Min除以317847191的余数,其中Max为当前数列中的最大数,Min为当前数列中的最小数,保证数列不为空。
T:输出数列中所有数的乘积除以317847191的余数,保证数列不为空。
输入格式:
第1行:两个正整数N,M,N表示初始数列的长度,M表示操作数。
第2行:N个正整数,第i个数表示初始数列中的第i项Ai,数列中有可能会有相同的数(如遇到删除操作,则只需要删去其中任意一个)。
第3~M+2行:每行表示一个操作,具体格式参见题目描述。
输出格式:
每行一个数,分别表示每个操作的结果(D x操作不需要有输出)。
输入样例
3 6
2 6 9
M
D 9
B
S
M
T
输出样例
81
6
2
36
12
说明
【数据规模】
49%的数据满足 N<=1000, M<=100, Ai<=4000
100%的数据满足N<=1000000, M<=1000000, Ai<=100000000
题目分析
其实本来想写treap,无奈我太水了总是MLE,所以只好写了二叉堆
其实主要问题就是对于T操作
删除数字除法不符合取膜运算律
所以这题最好用离线操作
先把最终状态的所有数加入
再倒叙处理询问存入栈内
这样就可以用一个全局变量记录所有数的乘积了
剩下的都输堆的基本操作了吧
#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long lt;
lt read()
{
lt f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return x*f;
}
const int maxn=2000010;
const lt mod=317847191;
int n,m;
lt d[maxn];
struct node{int k,x;}q[maxn];
lt mx[maxn],mi[maxn],cnt;//大根堆与小根堆
lt mul=1;
int judge[maxn];//判断第i位的数是否已删除
lt st[maxn],top;
void up(int pp)
{
int p=pp;
while(p>1)
{
if(mx[p]>mx[p>>1]){swap(mx[p],mx[p>>1]); p>>=1;}
else break;
}
p=pp;
while(p>1)
{
if(mi[p]<mi[p>>1]){swap(mi[p],mi[p>>1]); p>>=1;}
else break;
}
}
void ins(lt x)
{
mx[++cnt]=x; mi[cnt]=x;
up(cnt);
}
lt qpow(lt a,lt k)
{
lt ans=1;
while(k>0)
{
if(k&1) ans=(ans*a)%mod;
a=(a*a)%mod;
k>>=1;
}
return ans;
}
int main()
{
n=read();m=read();
for(int i=1;i<=n;++i) d[i]=read();
sort(d+1,d+1+n);//排序以便二分查找数的位置
for(int i=1;i<=m;++i)
{
char ss; scanf("%s",&ss);
if(ss=='D')
{
int x=read();
judge[lower_bound(d+1,d+1+n,x)-d]=1;//二分查找已删除的数位置
q[i].k=1; q[i].x=x;
}
else if(ss=='B') q[i].k=2;
else if(ss=='S') q[i].k=3;
else if(ss=='M') q[i].k=4;
else if(ss=='T') q[i].k=5;
}
for(int i=1;i<=n;++i)
if(!judge[i]){ ins(d[i]); mul=(mul*d[i])%mod;}//先插入没删除的数并记录乘积
for(int i=m;i>=1;--i)//倒序处理询问
{
if(q[i].k==1) { ins(q[i].x); mul=(mul*d[i])%mod;}
else if(q[i].k==2) st[++top]=mx[1];
else if(q[i].k==3) st[++top]=mi[1];
else if(q[i].k==4) st[++top]=qpow(mx[1],mi[1]);
else if(q[i].k==5) st[++top]=mul;
}
while(top) printf("%lld\n",st[top--]);
return 0;
}