动态排名系统(整体二分)

题面

第一道自己脑补出来的整体二分,这样我就不用去打那个树桩数组套主席树了

开心

主要是把各个操作分开

op==1 则为加操作

op==2 则为减操作

op==3则为区间查询操作

之后直接将询问的次数和值域二分求解即可

#include<bits/stdc++.h>
#define lowbit(x) x&(-x)
using namespace std;
const int N=1e5+7;
const int INF=1e9+7;
int m,n,T;
int ans[N],num[N];
struct node
{
    int x,y,id,op;
    int k;
} q[N],q1[N],q2[N];
struct Tree
{
    int tree[N<<2];
    void add(int x,int val)
    {
        for (;x<=n;x+=lowbit(x)) tree[x]+=val;
    }
    int query(int x)
    {
        int ans=0;
        for (;x;x-=lowbit(x)) ans+=tree[x];
        return ans;
    }
} G;

int cur[N];
void solve(int from,int to,int l,int r)
{
    if (from>to||l>r) return;
    if (l==r)
    {
        for (int i=from;i<=to;i++)
        if (q[i].op==3) ans[q[i].id]=l;
        return;
    }
    int mid=(l+r)>>1;
    for (int i=from;i<=to;i++)
    {
        if (q[i].k<=mid)
        {    
            if (q[i].op==2) G.add(q[i].x,-1);
            if (q[i].op==1) G.add(q[i].x,1);
        }
        if (q[i].op==3) cur[i]=G.query(q[i].y)-G.query(q[i].x-1);
    }
    for (int i=from;i<=to;i++)
    if (q[i].k<=mid)
    {
        if (q[i].op==2) G.add(q[i].x,1);
        if (q[i].op==1) G.add(q[i].x,-1);
    }
    int t1=0,t2=0;
    for (int i=from;i<=to;i++)
    if (q[i].op==1||q[i].op==2)
    {
        if (q[i].k<=mid) q1[t1++]=q[i];
        else q2[t2++]=q[i];
    }
    else 
    {
        if (cur[i]>=q[i].k) q1[t1++]=q[i];
        else q[i].k-=cur[i],q2[t2++]=q[i];
    }
    for (int i=0;i<t1;i++) q[from+i]=q1[i];
    for (int i=0;i<t2;i++) q[from+t1+i]=q2[i];
    solve(from,from+t1-1,l,mid);
    solve(from+t1,to,mid+1,r);
}
int main()
{
    freopen("dynrank.in","r",stdin);
    freopen("dynrank.out","w",stdout);
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++)
        {
            int x;scanf("%d",&x);
            q[i].op=1;q[i].x=i;q[i].k=x;num[i]=x;
        }
        int tot=0;
        for (int i=1;i<=m;i++)
        {
            char s[5];int x,y,k;
            scanf("%s",s);scanf("%d%d",&x,&y);
            if (s[0]=='Q') {scanf("%d",&k);q[++n].op=3;q[n].x=x;q[n].y=y;q[n].id=++tot;q[n].k=k;}
            if (s[0]=='C')
            {
                q[++n].op=2;q[n].x=x;q[n].k=num[x];
                q[++n].op=1;q[n].x=x;q[n].k=y;num[x]=y;
            }
        }
        solve(1,n,0,INF);
        for (int i=1;i<=tot;i++) 
        printf("%d
",ans[i]);
    }
    return 0;
}

 

慢即是快,细则是能,于小处铸迤逦
原文地址:https://www.cnblogs.com/Hale522520/p/10861732.html