[loj2736][JOISC 2016 Day3]回转寿司——分块+堆

题目大意:

给出一个有 \(N\) 个点的环,环上各点有一个初始权值\(a_i\)
给出 \(Q\) 个询问,每次询问给出一个区间 \([l,r]\) 和一个值 \(A\) ,对于 \(A\) 的变动定义如下(\(r\) 可能会小于 \(l\) 因为是环形):

for (int i = l; i <= r; i++) if(a[i] > A) swap(a[i],A);

对于每个询问,回答遍历完区间 \([l,r]\)\(A\) 的最终值。
注:我们按逆时针方向在环上编号,并规定 \([l,r]\)为从位置编号为 \(l\) 的点逆时针遍历至位置编号为 \(r\) 的点所经过点的集合。

思路:

这种看起来怎么都不好做的题目考虑分块。
对于这个操作,我们对于每一块显然只需要取出其中最大的元素即可,用一个堆来维护每一个块的中的元素。
但是对于边角块,修改的时候可以暴力修改,可我们也需要知道每一个元素的具体位置,于是这里有了一种重构的操作:
我们将每一次放入这个块内的元素记录下来,按照从小到大的顺序进行那种交换的操作,只考虑最终的结果,不难发现这样是正确的,用一个小根堆维护即可。
时间复杂度\(\Theta(n\sqrt {n}\log n)\)

#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
#define debug(x) cout<<#x<<"="<<x<<endl
typedef long long ll;

using namespace std;

void File(){
    freopen("in.in","r",stdin);
    freopen("in.out","w",stdout);
}

template<typename T>void read(T &_){
    T __=0,mul=1; char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')mul=-1;
        ch=getchar();
    }
    while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
    _=__*mul;
}

const int maxn=4e5+10;
const int maxb=800+10;
const int B=600;
int n,q,a[maxn],bel[maxn],L[maxb],R[maxb];
priority_queue<int>big[maxb];
priority_queue<int,vector<int>,greater<int> >small[maxb];

void rebuild(int id){
    if(small[id].empty())return;
    REP(i,L[id],R[id]){
        if(a[i]>small[id].top()){
            int t=small[id].top();
            small[id].pop();
            small[id].push(a[i]);
            a[i]=t;
        }
    }
    while(!small[id].empty())small[id].pop();
}

int modify_block(int l,int r,int x){
    int id=bel[l];
    REP(i,l,r)if(a[i]>x)swap(x,a[i]);
    while(!big[id].empty())big[id].pop();
    REP(i,L[id],R[id])big[id].push(a[i]);
    //REP(i,L[id],R[id])cout<<a[i]<<" ";
    //cout<<endl;
    return x;
}

int modify(int l,int r,int x){
    //debug(l); debug(r);
    int bl=bel[l],br=bel[r],t;
    rebuild(bel[l]); rebuild(bel[r]);
    if(bl==br)return modify_block(l,r,x);
    else{
        x=modify_block(l,R[bl],x);
        REP(i,bl+1,br-1)if(big[i].top()>x){
            t=big[i].top(); big[i].pop();
            big[i].push(x); small[i].push(x);
            x=t;
        }
        return modify_block(L[br],r,x);
    }
}

void init(){
    read(n); read(q);
    REP(i,1,n)read(a[i]);

    memset(L,63,sizeof(L));
    memset(R,-1,sizeof(R));
    REP(i,1,n){
        bel[i]=(i-1)/B+1;
        L[bel[i]]=min(L[bel[i]],i);
        R[bel[i]]=max(R[bel[i]],i);
    }

    REP(i,1,n)big[bel[i]].push(a[i]);
}

void work(){
    int l,r,x;
    REP(i,1,q){
        read(l),read(r),read(x);
        if(l<=r)printf("%d\n",modify(l,r,x));
        else printf("%d\n",modify(1,r,modify(l,n,x)));
    }
}

int main(){
    //File();
    init();
    work();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ylsoi/p/9845778.html