【JZOJ 5431】【NOIP2017提高A组集训10.28】序列操作

Description

一开始有n个非负整数hi,接下来会进行m次操作,第i次操作给出一个数c[i],要求你选出c[i]个大于零的数并将它们减去1。
问最多可以进行多少轮操作后无法操作(即没有c[i]个大于零的数)

Solution

暴力显然,就是每次找出前c[i]大的那些数,把他们都-1 (S)
那么这个就用Splay来维护即可,

但显然,不用Splay,直接用一棵线段树,不过在处理前段相同的数的时候要特判一下,

复杂度: O(nlog(n))

Code

#include 
#include 
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define min(q,w) ((q)>(w)?(w):(q))
#define max(q,w) ((q)<(w)?(w):(q))
#define SD(q) ((q)==b[b[q].fa].r)
using namespace std;
const int N=1000500,INF=2147483640;
int read(int &n)
{
    char ch=' ';int q=0,w=1;
    for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
    if(ch=='-')w=-1,ch=getchar();
    for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n,ans;
int a[N];
int root,b0;
struct qqww
{
    int l,r,fa,si;
    int cha,nm;
    int v,ans;
}b[N*3];
void merge(int q)
{
    b[q].si=b[b[q].l].si+1+b[b[q].r].si;
    b[q].ans=b[b[q].l].ans+b[q].v+b[b[q].r].ans;
    b[q].nm=b[b[q].l].nm+b[q].cha+b[b[q].r].nm;
}
void rotate(int q)
{
    int w=b[q].fa;
    if(SD(q))
    {
        b[w].r=b[q].l;
        b[b[q].l].fa=w;
        b[q].l=w;
    }else
    {
        b[w].l=b[q].r;
        b[b[q].r].fa=w;
        b[q].r=w;
    }
    if(SD(w))b[b[w].fa].r=q;
    else b[b[w].fa].l=q;
    b[q].fa=b[w].fa;
    b[w].fa=q;
    merge(w);
    merge(q);
}
void Splay(int q,int T)
{
    for(;b[q].fa!=T;)
    {
        if(b[b[q].fa].fa!=T)
        {
            if(SD(q)==SD(b[q].fa))rotate(b[q].fa);
            else rotate(q);
        }
        rotate(q);
    }
    if(!T)root=q;
}
int BHn,hos,nm;
int findT(int q,int si)
{
    if(b[b[q].r].ans>=si)
    {
        nm+=b[b[q].l].nm+b[q].cha;
        BHn+=b[b[q].l].si+1;
        return findT(b[q].r,si);
    }
    hos=si-b[b[q].r].ans;
    si-=b[b[q].r].ans+b[q].v;
    if(si<1)
    {
        BHn+=b[b[q].l].si+1;
        nm+=b[b[q].l].nm+b[q].cha;
        return q;
    }
    return findT(b[q].l,si);
}
int findS(int q,int si)
{
    if(b[b[q].l].si>=si)return findS(b[q].l,si);
    si-=b[b[q].l].si+1;
    if(si<1)return q;
    return findS(b[q].r,si);
}
int findnm(int q,int si)
{
    if(b[b[q].l].nm+b[q].cha>si&&b[q].l)return findnm(b[q].l,si);
    si-=b[b[q].l].nm+b[q].cha;
    if(si<1)return q;
    return findnm(b[q].r,si);
}
void DLT(int q)
{
    Splay(findS(root,q-1),0);
    if(b[b[root].r].si<2)
    {
        b[b[root].r].fa=0;
        b[root].r=0;
        merge(root);
        return;
    }
    Splay(q=findS(root,q+1),root);
    b[b[q].l].fa=0;
    b[q].l=0;
    merge(q),merge(root);
}
void ADD1(int q,int w)
{
    if(!w)return;
    Splay(findnm(root,q),0);
    if(b[b[root].l].nm+b[root].cha==q)
    {
        b[root].v+=w;
    }else
    {
        b0++;
        b[b0].fa=root;
        b[b0].l=b[root].l;
        b[b[root].l].fa=b0;
        b[root].l=b0;
        b[b0].cha=q-b[b[b0].l].nm;
        b[root].cha-=b[b0].cha;
        b[b0].v=w;
        merge(b[b0].l);
        merge(b0);
    }
    merge(root);
}
void Jian(int q,int w)
{
    if(!w)return;
    Splay(q,0);
    b[q].v-=w;
    merge(root);
}
int main()
{
    freopen("sequence.in","r",stdin);
    freopen("sequence.out","w",stdout);
    int q,w,_;
    read(n),read(_);
    fo(i,1,n)read(a[i]);
    sort(a+1,a+1+n);
    b[b0=1].v=1e9;
    q=0;
    fo(i,1,n)if(a[i]!=a[i+1])
    {
        b0++;
        b[b0].fa=b0-1,b[b0-1].r=b0;
        b[b0].v=i-q;b[b0].cha=a[i]-a[q];
        q=i;
    }
    b[b0].r=b0+1;
    b[b0+1].fa=b0;
    b[b0+1].cha=1e9;merge(b0+1);
    b0++;
    fod(i,b0,1)merge(i);
    Splay(b0/2,0);
    root=b0/2;
    bool BR=0;
    fo(I,1,_)
    {
        read(w);
        BHn=nm=hos=0;
        q=findT(root,w);
        if(q<2){BR=1;printf("%d\n",I-1);break;}
        if(b[q].cha==1)
        {
            DLT(BHn);
            ADD1(nm,b[q].v-hos);
            ADD1(nm-1,hos);
        }else
        {
            Splay(q,0);
            b[q].cha--;
            merge(q);
            int t=b[q].v;
            Jian(q,b[q].v-hos);
            ADD1(nm,t-hos);
        }
    }
    if(!BR)printf("%d\n",_);
    return 0;
}

你可能感兴趣的:(杂题)