[分块 块的分裂 || 替罪羊树套线段树] BZOJ 3065 带插入区间K小值

省选时收了分块大师的教导

于是用分块过了这题 当时竟然没有发上来

具体快忘完了 只是记得分裂什么的


#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef pair<int,int> abcd;
 
inline char nc()
{
    static char buf[100000],*p1=buf,*p2=buf;
    if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
    return *p1++;
}
 
inline void read(int &x)
{
    char c=nc(),b=1;
    for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
    for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
 
inline void read(char &x)
{
    for (x=nc();!(x=='Q' || x=='M' || x=='I');x=nc());
}
 
inline double Log(int x){
    return log(x)/log(2);
}
 
int n,lastans;
int inum[35005];
int B,cnt;
int nxt[1005],tot[1005];
int a[1005][1005],b[1005][1005];
 
inline abcd kth(int k){
    for (int i=1;i;i=nxt[i])
    {
        if (!nxt[i] && k>tot[i])
            return abcd(i,k);
        if (k>tot[i])
            k-=tot[i];
        else
            return abcd(i,k);
    }
}
 
int l,r,K,x,val,ipos,idx;
abcd lp,rp,pos;
 
inline bool check(int mid,int K){
    int ret=0;
    if (lp.first==rp.first)
    {
        for (int i=lp.second;i<=rp.second;i++)
            if (a[lp.first][i]<=mid)
                ret++;
        return ret>=K;
    }
    for (int i=lp.second;i<=tot[lp.first];i++)
        if (a[lp.first][i]<=mid)
            ret++;
    for (int i=1;i<=rp.second;i++)
        if (a[rp.first][i]<=mid)
            ret++;
    for (int i=nxt[lp.first];i!=rp.first;i=nxt[i])
        ret+=upper_bound(b[i]+1,b[i]+tot[i]+1,mid)-b[i]-1;
    return ret>=K;
}
 
inline void Query()
{
    read(l); read(r); read(K);
    l^=lastans; r^=lastans; K^=lastans;
    lp=kth(l),rp=kth(r);
    int L=-1,R=70000,MID;
    while (L+1<R)
        if (check(MID=(L+R)>>1,K))
            R=MID;
        else
            L=MID;
    printf("%d\n",lastans=R);
//  lastans=0;
}
 
inline void Modify()
{
    int last;
    read(x); read(val); 
    x^=lastans; val^=lastans;
    pos=kth(x);
    idx=pos.first;
    last=a[idx][pos.second];
    a[idx][pos.second]=val;
    ipos=lower_bound(b[idx]+1,b[idx]+tot[idx]+1,last)-b[idx];
    b[idx][ipos]=val;
    while (ipos-1>=1 && b[idx][ipos]<b[idx][ipos-1]) 
        swap(b[idx][ipos],b[idx][ipos-1]),ipos--;
    while (ipos+1<=tot[idx] && b[idx][ipos]>b[idx][ipos+1]) 
        swap(b[idx][ipos],b[idx][ipos+1]),ipos++;
}
 
inline void Death(int p)
{
    ++cnt;
    for (int i=B+1;i<=tot[p];i++)
        a[cnt][++tot[cnt]]=a[p][i],b[cnt][tot[cnt]]=a[cnt][tot[cnt]],a[p][i]=0;
    sort(b[cnt]+1,b[cnt]+tot[cnt]+1);
    tot[p]-=B;
    for (int i=1;i<=tot[p];i++)
        b[p][i]=a[p][i];
    sort(b[p]+1,b[p]+tot[p]+1);
    nxt[cnt]=nxt[p]; nxt[p]=cnt;
}
 
inline void Insert()
{
    read(x); read(val); 
    x^=lastans; val^=lastans;
    pos=kth(x);
    idx=pos.first;
    for (int i=tot[idx];i>=pos.second;i--)
        a[idx][i+1]=a[idx][i];
    a[idx][pos.second]=val;
    b[idx][ipos=++tot[idx]]=val;
    while (ipos-1>=1 && b[idx][ipos]<b[idx][ipos-1]) 
        swap(b[idx][ipos],b[idx][ipos-1]),ipos--;
    if (tot[idx]>=2*B)
        Death(idx);
}
 
int main()
{
	freopen("t.in","r",stdin);
	freopen("t.out","w",stdout);
    int Q;
    char order;
    read(n);
    for (int i=1;i<=n;i++) read(inum[i]);
    B=sqrt(n); cnt=(n-1)/B+1;
    for (int i=1;i<=n;i++)
    {
        ipos=(i-1)/B+1;
        a[ipos][++tot[ipos]]=inum[i];
        b[ipos][tot[ipos]]=inum[i];
    }
    for (int i=1;i<=cnt;i++)
        nxt[i]=i+1;
    nxt[cnt]=0;
    for (int i=1;i<=cnt;i++)
        sort(b[i]+1,b[i]+tot[i]+1);
    read(Q);
    while (Q--)
    {
        read(order);
        if (order=='Q')
            Query();
        else if (order=='M')
            Modify();
        else if (order=='I')
            Insert();
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值