牛客13819 Honorable Mention

链接

点击跳转

题解

自闭了一下午,难受,全在调试splay板子

分析题目,发现:

如果一个队本来就打铁,过了题之后还打铁,那么我压根不用管

如果一个队本来就有牌,过了题之后还有牌,那么我需要维护下新的排名序列

如果一个队本来打铁,过题之后有牌了,那我需要把他从“打铁集合”当中删掉,然后加入“有牌集合”

因为打铁的队伍我并不关心他们的排名,所以用一个树状数组,以序号为下标维护下前缀和就行了。

而有牌的队伍,我需要维护一下他们的先后关系,所以需要一个平衡树

代码

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define iinf 0x3f3f3f3f
#define linf (1ll<<60)
#define eps 1e-8
#define maxn 100010
#define cl(x) memset(x,0,sizeof(x))
#define rep(i,a,b) for(i=a;i<=b;i++)
#define drep(i,a,b) for(i=a;i>=b;i--)
#define em(x) emplace(x)
#define emb(x) emplace_back(x)
#define emf(x) emplace_front(x)
#define fi first
#define se second
#define de(x) cerr<<#x<<" = "<<x<<endl
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
ll read(ll x=0)
{
    ll c, f(1);
    for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
    for(;isdigit(c);c=getchar())x=x*10+c-0x30;
    return f*x;
}
struct Splay
{
    typedef int T;
    int root, cnt[maxn], ch[maxn][2], f[maxn], size[maxn], tot;
    T v[maxn];
    void clear()
    {
        for(int i=1;i<=tot;i++)f[i]=cnt[i]=size[i]=ch[i][0]=ch[i][1]=0;
        root=tot=0;
    }
    void pushup(int x)
    {
        size[x]=cnt[x]+size[ch[x][0]]+size[ch[x][1]];
    }
    int get(int x){return ch[f[x]][1]==x;}
    void rotate(int x)
    {
        int y=f[x], z=f[y], t=get(x);
        f[ch[x][!t]]=y, ch[y][t]=ch[x][!t];
        f[x]=z, ch[z][get(y)]=x;
        f[y]=x, ch[x][!t]=y;
        pushup(y);
        pushup(x);
    }
    void splay(int x, int goal=0)
    {
        while(f[x]!=goal)
        {
            if(f[f[x]]!=goal)rotate(get(x)==get(f[x])?f[x]:x);
            rotate(x);
        }
        if(!goal)root=x;
    }
    int insert(T x)
    {
        int now=root, pp=0;
        while(now and v[now]!=x)
        {
            pp = now;
            now = ch[now][x>v[now]];
        }
        if(now)cnt[now]++;
        else
        {
            cnt[now=++tot]=1;
            v[now]=x;
            f[now]=pp;
            ch[pp][x>v[pp]]=now;
        }
        splay(now);
        return now;
    }
    int find(T x)
    {
        int now;
        for(now=root;v[now]!=x;now=ch[now][x>v[now]]);
        splay(now);
        return now;
    }
    int kth(int k)
    {
        int now=root, lsz, rsz;
        while(true)
        {
            lsz = size[ch[now][0]], rsz = size[ch[now][1]];
            if(lsz+cnt[now]>=k)
            {
                if(lsz<k)return now;
                else now=ch[now][0];
            }
            else
            {
                k -= lsz+cnt[now];
                now = ch[now][1];
            }
        }
    }
    int pre(int x)
    {
        splay(x);
        int now;
        for(now=ch[x][0];ch[now][1];now=ch[now][1]);
        splay(now);
        return now;
    }
    int suc(int x)
    {
        splay(x);
        int now;
        for(now=ch[x][1];ch[now][0];now=ch[now][0]);
        splay(now);
        return now;
    }
    void erase(int x)
    {
        if(cnt[x]>1){cnt[x]--;splay(x);return;}
        int p=pre(x), s=suc(x);
        splay(p), splay(s,p);
        ch[s][0]=f[x]=0;
        pushup(s), pushup(p);
    }
}splay;
struct BIT
{
    ll bit[maxn], n;
    void init(int N){n=N;for(int i=1;i<=n;i++)bit[i]=0;}
    ll lowbit(ll x){return x&(-x);}
    void add(ll pos, ll v)
    {
        for(;pos<=n;pos+=lowbit(pos))bit[pos]+=v;
    }
    ll sum(ll pos)
    {
        ll ans(0);
        for(;pos;pos-=lowbit(pos))ans+=bit[pos];
        return ans;
    }
}bit;
int main()
{
    int T=read();
    while(T--)
    {
        int n=read(), i;
        vector<ll> p(n+5), num(n+5), q(n+5);
        int fe = n*6/10+1;
        splay.clear();
        int last = splay.insert(-iinf);
        int ed = splay.insert(iinf);
        bit.init(n);
        rep(i,1,n)
        {
            p[i]=read();
            if(p[i]>=fe)
            {
                bit.add(i,+1);
                num[i]=-1;
            }
            else
            {
                q[p[i]]=i;
            }
        }
        rep(i,1,fe-1)
        {
            splay.splay(last);
            splay.splay(ed,last);
            
            int x = ++splay.tot;
            num[q[i]] = x;
            splay.v[x] = q[i];
            splay.cnt[x] = splay.size[x] = 1;
            splay.f[x] = ed;

            splay.ch[ed][0] = x;

            splay.pushup(ed);
            splay.pushup(last);
            
            last = x;
        }
        int Q=read();
        while(Q--)
        {
            int op=read(), x=read(), y=read();
            if(op==2)
            {
                printf("%lld\n",bit.sum(y)-bit.sum(x-1));
            }
            else
            {
                if(y<fe)
                {
                    if(num[x]!=-1)
                    {
                        splay.erase(num[x]);
                        num[x] = -1;
                    }
                    else
                    {
                        bit.add(x,-1);
                    }

                    int pre = splay.kth(y), suc = splay.suc(pre), t = ++splay.tot;
                    splay.splay(pre), splay.splay(suc,pre);

                    num[x] = t;
                    splay.v[t] = x;
                    splay.cnt[t] = splay.size[t] = 1;
                    splay.f[t] = suc;

                    splay.ch[suc][0] = t;

                    splay.pushup(suc);
                    splay.pushup(pre);

                    if(fe>1 and splay.size[splay.root]==fe+2)
                    {
                        int datie = splay.kth(fe+1);
                        if(splay.v[datie]>n)de(n),de(datie),de(fe),de(splay.size[splay.root]);
                        num[ splay.v[datie] ] = -1;
                        bit.add(splay.v[datie],+1);
                        splay.erase( datie );
                    }
                }
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值