[loj2461]完美的队列

版权声明:本文是蒟蒻写出来的,神犇转载也要说一声哦! https://blog.csdn.net/WerKeyTom_FTD/article/details/79800048

题目大意

有n个队列,每个队列有一个上限ai
当队列上限满时,如果还要push,其会先执行一次pop。
现在有m个操作。
每次操作都会给一个区间的队列push同一个x。
要求回答每次操作后所有队列中数的种类数。

做法

当一个数x进入第i个队列,这个队列再push ai次会pop掉这个x
这个非常显然。
现在对于每个操作,我们需要知道最早在第几次操作后,这次操作加入的x全部被pop,就得到了这个x的存在时间。
接下来对于同一个x的若干存在时间取并,差分前缀和可以算出答案。
于是难点在求出什么时候pop完。
我们将序列分块,然后先考虑对于每个操作求出其所覆盖的每个整块什么时候pop完,再求出散块中每个位置什么时候pop完。
我们枚举一个整块,然后考虑顺序枚举操作j,同时维护一个指针k,表示执行(j,k]的操作可以把每个位于整块的位置弹完。假如能维护出这个指针k,显然如果操作j包含这个整块,就可以将k和j的答案取max。
维护的具体是我们对整块内每个元素维护一个val,初始为a,表示执行了(j,k]后的散块操作其还有多少次才能弹完,同时维护val中的mx。用ad表示(j,k]中有多少操作覆盖了整块,那么当mx-ad<=0时,k是合法的。
增加一个操作时,如果其完整覆盖了这个整块,让ad++。否则如果其与该整块有交,暴力将交的部分的val–,并更新mx,减少一个操作同理。
对于一个操作,其只会贡献2 sqrt n的暴力改val。
接下来解决散块。
在处理整块时可以维护出一个前缀和,表示覆盖整块的次数。
同样要维护每种前缀和第一次出现的位置。
现在我们枚举一个位置,把散块包含其的操作提出来,同样two-pointer,然后用上面提到的两个信息就可以了。详见代码。
复杂度一个根号。

#include<cstdio>
#include<algorithm>
#include<queue>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=100000+10,B=3;
int belong[maxn],val[maxn],sum[maxn],fi[maxn];
int L[maxn],R[maxn],data[maxn],a[maxn],b[maxn],c[maxn],id[maxn];
struct dong{
    int x,y,v;
    friend bool operator <(dong a,dong b){
        return a.x<b.x||a.x==b.x&&a.y<b.y;
    }
} p[maxn*4];
queue<int> dl[maxn];
int i,j,k,l,r,t,n,m,tot,top,ad,mx,len;
int read(){
    int x=0,f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9'){
        if (ch=='-') f=-1;
        ch=getchar();
    }
    while (ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
void ins(int id,int f){
    if (id>m) return;
    if (L[id]<=l&&R[id]>=r){
        ad+=f;
        return;
    }
    else if (R[id]<l||L[id]>r) return;
    int i,j=l,k=r;
    j=max(j,L[id]);
    k=min(k,R[id]);
    fo(i,j,k) val[i]-=f;
    mx=0;
    fo(i,l,r) mx=max(mx,val[i]);
}
void work(int p,int q){
    int i,j,k;
    fo(i,p,q){
        tot=0;
        while (!dl[i].empty()){
            id[++tot]=dl[i].front();
            dl[i].pop();
        }
        k=0;
        fo(j,1,tot){
            while (k<=tot&&sum[id[k]]-sum[id[j]]+k-j<a[i]) k++;
            if (k>tot){
                t=a[i]-(tot-j)+sum[id[j]];
                if (t>len) b[id[j]]=m+1;
                else b[id[j]]=max(b[id[j]],fi[t]);
            }
            else{
                if (sum[id[k]]-sum[id[j]]+k-j==a[i]) b[id[j]]=max(b[id[j]],id[k]);
                else{
                    t=a[i]-(k-j-1)+sum[id[j]];
                    t=fi[t];
                    b[id[j]]=max(b[id[j]],t);
                }
            }
        }
    }
}
int main(){
    freopen("data.in","r",stdin);freopen("data.out","w",stdout);
    n=read();m=read();
    fo(i,1,n) a[i]=read();
    fo(i,1,m){
        L[i]=read();R[i]=read();
        data[i]=read();
        mx=max(mx,data[i]);
    }
    top=mx;
    fo(i,1,n) belong[i]=(i-1)/B+1;
    fo(i,1,m){
        l=belong[L[i]];r=belong[R[i]];
        if (l==r){
            if ((l-1)*B+1==L[i]&&min(r*B,n)==R[i]) continue;
            fo(j,L[i],R[i]) dl[j].push(i);
        }
        else{
            if (L[i]!=(l-1)*B+1) fo(j,L[i],l*B) dl[j].push(i);
            if (R[i]!=min(r*B,n)) fo(j,(r-1)*B+1,R[i]) dl[j].push(i);
        }
    }
    fo(i,1,belong[n]){
        l=(i-1)*B+1;r=min(i*B,n);
        ad=mx=0;
        fo(j,l,r){
            val[j]=a[j];
            mx=max(mx,a[j]);
        }
        ins(k=1,1);
        fo(j,1,m){
            ins(j,-1);
            while (k<=m&&mx-ad>0) ins(++k,1);
            if (L[j]<=l&&r<=R[j]) b[j]=max(b[j],k);
        }
        fo(j,1,m){
            sum[j]=sum[j-1];
            if (L[j]<=l&&r<=R[j]){
                sum[j]++;
                fi[sum[j]]=j;
            }
        }
        len=sum[m];
        work(l,r);
    }
    tot=0;
    fo(i,1,m){
        tot++;
        p[tot].x=data[i];
        p[tot].y=i;
        p[tot].v=1;
        tot++;
        p[tot].x=data[i];
        p[tot].y=b[i];
        p[tot].v=-1;
    }
    mx=top;
    fo(i,1,mx){
        tot++;
        p[tot].x=i;
        p[tot].y=1;
        p[tot].v=0;
        tot++;
        p[tot].x=i;
        p[tot].y=m+1;
        p[tot].v=0;
    }
    sort(p+1,p+tot+1);
    r=0;
    fo(i,1,mx){
        t=0;
        l=r+1;
        while (r<tot&&p[r+1].x==i) r++;
        fo(j,l,r-1){
            t+=p[j].v;
            if (t){
                c[p[j].y]++;
                c[p[j+1].y]--;
            }
        }
    }
    t=0;
    fo(i,1,m){
        t+=c[i];
        printf("%d\n",t);
    }
}
阅读更多
换一批

没有更多推荐了,返回首页