【NOI2017模拟6.23】回转寿司

来源:互联网 发布:linux 注销登录用户 编辑:程序博客网 时间:2024/04/29 13:46

题目大意

有n个人排成一个圆环,每个人初始有一个数字a[i],有m轮操作,每轮操作选择一段连续的人并给出一个数字x,按顺时针顺序比较x和a[i],如果x小于a[i],就那么交换a[i]和x
1n4×105
1m2.5104

解法

考虑分块,那么对于一个块来说,如果当前某个数x进去了,那么出来的要不是x要不就是这个块的最大值,所以对每个块维护一个大根堆。
而对于块内的重构,由于本题有很好的性质:标记的处理和a[]的变化是具有对称性的,就是说重构时只要维护一个对于标记的小根堆,然后从左到右扫一遍。

Code

#include<iostream>#include<cstring>#include<cstdio>#include<algorithm>#include<cmath>#include<set>#include<bitset>#include<map>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)using namespace std;typedef long long LL;typedef double db;int get(){    char ch;    while(ch=getchar(),(ch<'0'||ch>'9')&&ch!='-');    if (ch=='-'){        int s=0;        while(ch=getchar(),ch>='0'&&ch<='9')s=s*10+ch-'0';        return -s;    }    int s=ch-'0';    while(ch=getchar(),ch>='0'&&ch<='9')s=s*10+ch-'0';    return s;}const int N = 400010;const int Q = 25010;const int blk = 635;const int B = 640;int n,q;struct heap0{    int a[B];    int n;    int& operator [](int x){return a[x];}    int top(){return a[1];}    void pop(){        int x=1;        a[1]=a[n--];        while(x*2<=n){            int t=x*2;            if (t<n&&a[t+1]>a[t])t++;            if (a[t]<=a[x])break;            swap(a[t],a[x]);            x=t;        }    }    void insert(int v){        a[++n]=v;        int x=n;        while(x>1&&a[x]>a[x>>1]){            swap(a[x],a[x>>1]);            x>>=1;        }    }}a[B];struct heap1{    int a[Q];    int n;    int& operator [](int x){return a[x];}    int top(){return a[1];}    void pop(){        int x=1;        a[1]=a[n--];        while(x*2<=n){            int t=x*2;            if (t<n&&a[t+1]<a[t])t++;            if (a[t]>=a[x])break;            swap(a[t],a[x]);            x=t;        }    }    void insert(int v){        a[++n]=v;        int x=n;        while(x>1&&a[x]<a[x>>1]){            swap(a[x],a[x>>1]);            x>>=1;        }    }}t[B];int be[N],rig[N],lef[N];int val[N];void rebuild(int x){    a[x].n=0;    if (!t[x].n)return;    fo(i,lef[x],rig[x]){        int tp=t[x].top();        if (tp<val[i]){            t[x].pop();            t[x].insert(val[i]);            val[i]=tp;        }    }    t[x].n=0;}void putnew(int x){    a[x].n=0;    fo(i,lef[x],rig[x])a[x][++a[x].n]=val[i];    sort(a[x].a+1,a[x].a+a[x].n+1);    fo(i,1,a[x].n/2)swap(a[x][a[x].n-i+1],a[x][i]);}void solve(int l,int r,int &v){    if (be[l]==be[r]){        rebuild(be[l]);        fo(i,l,r)        if (v<val[i])swap(v,val[i]);        putnew(be[l]);        return;    }    int lt=be[l],rt=be[r];    if (l>lef[lt]){        rebuild(lt);        for(int i=l;be[i]==lt;i++)        if (v<val[i])swap(v,val[i]);        putnew(lt);        lt++;    }    if (r<rig[rt]){        fo(i,lt,rt-1){            int tp=a[i].top();            if (v<tp){                a[i].pop();                a[i].insert(v);                t[i].insert(v);                v=tp;            }        }        rebuild(rt);        fo(i,rig[rt-1]+1,r)        if (v<val[i])swap(v,val[i]);        putnew(rt);    }    else        fo(i,lt,rt){            int tp=a[i].top();            if (v<tp){                a[i].pop();                a[i].insert(v);                t[i].insert(v);                v=tp;            }        }}int main(){    freopen("sushi.in","r",stdin);    freopen("sushi.out","w",stdout);    n=get();q=get();    fo(i,1,n)be[i]=i/blk+1;    fo(i,1,n)rig[be[i]]=i;    fd(i,n,1)lef[be[i]]=i;    fo(i,1,n){        int x=get();        val[i]=x;        a[be[i]].insert(x);    }    fo(cas,1,q){        int l=get(),r=get(),v=get();        if (l>r){            solve(l,n,v);            solve(1,r,v);        }        else solve(l,r,v);        printf("%d\n",v);    }    fclose(stdin);    fclose(stdout);    return 0;}