洛谷 P2174 小Z的神奇数列【二叉堆】

题目描述

小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;
}

猜你喜欢

转载自blog.csdn.net/niiick/article/details/80272307
今日推荐