BZOJ 3065 带插入区间K小值

2 篇文章 0 订阅
1 篇文章 0 订阅

3065: 带插入区间K小值
Time Limit: 60 Sec Memory Limit: 512 MB
Submit: 3543 Solved: 1140
[Submit][Status][Discuss]
Description

从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i]。跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴。这时跳蚤国王决定理性愉悦一下,查询区间k小值。他每次向它的随从伏特提出这样的问题: 从左往右第x个到第y个跳蚤中,a[i]第k小的值是多少。
这可难不倒伏特,他在脑袋里使用函数式线段树前缀和的方法水掉了跳蚤国王的询问。
这时伏特发现有些跳蚤跳久了弹跳力会有变化,有的会增大,有的会减少。
这可难不倒伏特,他在脑袋里使用树状数组套线段树的方法水掉了跳蚤国王的询问。(orz 主席树)
这时伏特发现有些迟到的跳蚤会插入到这一行的某个位置上,他感到非常生气,因为……他不会做了。
请你帮一帮伏特吧。
快捷版题意:带插入、修改的区间k小值在线查询。

Input

第一行一个正整数n,表示原来有n只跳蚤排成一行做早操。
第二行有n个用空格隔开的非负整数,从左至右代表每只跳蚤的弹跳力。
第三行一个正整数q,表示下面有多少个操作。
下面一共q行,一共三种操作对原序列的操作:(假设此时一共m只跳蚤)
1. Q x y k: 询问从左至右第x只跳蚤到从左至右第y只跳蚤中,弹跳力第k小的跳蚤的弹跳力是多少。
(1 <= x <= y <= m, 1 <= k <= y - x + 1)
2. M x val: 将从左至右第x只跳蚤的弹跳力改为val。
(1 <= x <= m)
3. I x val: 在从左至右第x只跳蚤的前面插入一只弹跳力为val的跳蚤。即插入后从左至右第x只跳蚤是我刚插入的跳蚤。
(1 <= x <= m + 1)

为了体现在线操作,设lastAns为上一次查询的时候程序输出的结果,如果之前没有查询过,则lastAns = 0。
则输入的时候实际是:
Q _x _y _k ——> 表示 Q _x^lastAns _y^lastAns _k^lastAns
M _x _val ——> 表示 M _x^lastAns _val^lastAns
I _x _val ——> 表示 I _x^lastAns _val^lastAns
简单来说就是操作中输入的整数都要异或上一次询问的结果进行解码。

(祝Pascal的同学早日转C++,就不提供pascal版的描述了。)

Output

对于每个询问输出回答,每行一个回答。

Sample Input
10

10 5 8 28 0 19 2 31 1 22

30

I 6 9

M 1 11

I 8 17

M 1 31

M 6 26

Q 2 7 6

I 23 30

M 31 7

I 22 27

M 26 18

Q 26 17 31

I 5 2

I 18 13

Q 3 3 3

I 27 19

Q 23 23 30

Q 5 13 5

I 3 0

M 15 27

Q 0 28 13

Q 3 29 11

M 2 8

Q 12 5 7

I 30 19

M 11 19

Q 17 8 29

M 29 4

Q 3 0 12

I 7 18

M 29 27

Sample Output
28

2

31

0

14

15

14

27

15

14

HINT

此题作为一个小小的研究来搞吧~做法有很多~不知道这题究竟有多少种做法。

请自觉O(log^2n),我故意卡块状链表,块链A了的请受我深情一拜……

A掉的同学请在Discuss里面简要说下自己的做法吧~

原序列长度 <= 35000

插入个数 <= 35000,修改个数 <= 70000,查询个数 <= 70000 ,0 <= 每时每刻的权值 <= 70000

由于是OJ上的题,所以数据无梯度。为了防止卡OJ,本题只有4组数据。

Source

作者 vfleaking


终于A了这道题好开心QwQ
我写的是替罪羊树套线段树,写线段树合并和暴力插入都是22s…感觉自己写的有问题,但又想不出更好的方法。
平衡因子好像影响挺大的。0.73是30s,0.77是24s,0.8是22s,(0.8,0.85]是23s。
好多细节错误调了好久…好不容易对拍过了bzoj又炸了几个小时…
回收挺好写的。不知道为什么代码那么长。

总结一下bzoj上错误的可能性:
RE 数组开小
TLE+0ms 超过空间限制
TLE 看一下文件输入输出删掉了没有= =

暴力插入

#include <bits/stdc++.h>
#define N 70010
#define M 10000010
#define alpha 0.8
#define mid ((l+r)>>1)
#define K 70000
using namespace std;
int n,m,a[N],cnt;

template <class Aqua>
inline void read(Aqua &s){
    s=0; char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) s=s*10+c-'0',c=getchar();
}

struct seg{
    seg *ch[2];
    int s;
}t[M],*tail=t+1;
vector<int> res,v;
vector<seg*> q;

seg *newnode(){
    if (!res.size()){
        tail->ch[0]=tail->ch[1]=t;
        tail->s=0;
        return tail++;
    }
    else{
        seg *node=t+res.back();
        res.pop_back();
        node->ch[0]=node->ch[1]=t;
        node->s=0;
        return node;
    }
}

void raclaim(seg *&cur){
    if (cur==t) return;
    res.push_back(cur-t);
    raclaim(cur->ch[0]),raclaim(cur->ch[1]);
    cur=t;
}

void add(seg *&cur,int l,int r,int x,int d){
    if (cur==t) cur=newnode();
    cur->s+=d;
    if (l==r) return;
    if (x<=mid)
        add(cur->ch[0],l,mid,x,d);
    else
        add(cur->ch[1],mid+1,r,x,d);
    if (!cur->s)
        raclaim(cur),cur=t;
}

struct tree{
    tree *ch[2],*fa;
    seg *root; int size,x;
}T[N],*root=T,*tail_=T+1,*tmp=T,*b[N];

tree *newnode_(){
    tail_->ch[0]=tail_->ch[1]=tail_->fa=T;
    tail_->size=1; tail_->root=t;
    return tail_++;
}

void build(tree *&cur,int l,int r,tree *fa){
    if (l>r){
        cur=T; return;
    }
    cur=b[mid]; cur->x=a[mid]; cur->fa=fa;
    for (int i=l;i<=r;i++)
        add(cur->root,0,K,a[i],1);
    if (l==r){
        cur->size=1; cur->ch[0]=cur->ch[1]=T;
        return;
    }
    build(cur->ch[0],l,mid-1,cur);
    build(cur->ch[1],mid+1,r,cur);
    cur->size=cur->ch[0]->size+cur->ch[1]->size+1;
}

int select(tree *cur,int k){
    return (cur->ch[0]->size+1==k?cur->x:(cur->ch[0]->size>=k?select(cur->ch[0],k):select(cur->ch[1],k-cur->ch[0]->size-1)));
}

void modify(tree *cur,int k,int x,int d){
    add(cur->root,0,K,x,d);
    if (cur->ch[0]->size+1==k){
        cur->x=x; return;
    }
    else
        if (cur->ch[0]->size>=k)
            modify(cur->ch[0],k,x,d);
        else
            modify(cur->ch[1],k-cur->ch[0]->size-1,x,d);
}

void insert(tree *&cur,int k,int x,tree *fa){
    if (cur==T){
        cur=newnode_();
        cur->x=x; cur->fa=fa;
        add(cur->root,0,K,x,1);
        return;
    }
    add(cur->root,0,K,x,1);
    cur->size++;
    if (cur->ch[0]->size+1>k)
        insert(cur->ch[0],k,x,cur);
    else
        insert(cur->ch[1],k-cur->ch[0]->size-1,x,cur);
    if (max(cur->ch[0]->size,cur->ch[1]->size)>cur->size*alpha)
        tmp=cur;
}

void query(tree *cur,int l,int r,int L,int R){
    if (l>r) return;
    if (L<=l && r<=R){
        q.push_back(cur->root);
        return;
    }
    int Mid=l+cur->ch[0]->size;
    if (Mid>L)
        query(cur->ch[0],l,Mid-1,L,R);
    if (Mid>=L && Mid<=R)
        v.push_back(cur->x);
    if (Mid<R)
        query(cur->ch[1],Mid+1,r,L,R);
}

int Query(int l,int r,int k){
    q.clear(); v.clear();
    query(root,1,root->size,l,r);
    int s=0,x;
    for (l=0,r=K;l<r;s=0){
        for (int i=0;i<q.size();i++)
            s+=q[i]->ch[0]->s;
        for (int i=0;i<v.size();i++)
            if (v[i]>=l && v[i]<=mid)
                s++;
        if (s>=k)
            r=mid,x=0;
        else
            k-=s,l=mid+1,x=1;
        for (int i=0;i<q.size();i++)
            q[i]=q[i]->ch[x];
    }
    return l;
}

void dfs(tree *cur){
    if (cur==T) return;
    dfs(cur->ch[0]);
    a[++cnt]=cur->x,b[cnt]=cur;
    dfs(cur->ch[1]);
    raclaim(cur->root);
}

void rebuild(tree *cur){
    cnt=0; dfs(cur);
    tree *fa=cur->fa;
    if (fa==T)
        build(root,1,cnt,T);
    else
        build(fa->ch[(fa->ch[0]==cur)?0:1],1,cnt,fa);
}

int main(){
    read(n);
    for (int i=1;i<=n;i++)
        read(a[i]),b[i]=newnode_();
    T->size=0; T->root=t;
    t->ch[0]=t->ch[1]=t; t->s=0;
    build(root,1,n,T);
    read(m);
    char s[10]; int x,y,k,las=0;
    for (int i=1;i<=m;i++){
        scanf("%s",s);
        if (s[0]=='Q'){
            read(x),read(y),read(k);
            x^=las,y^=las,k^=las;
            printf("%d\n",las=Query(x,y,k));
        }
        if (s[0]=='M'){
            read(x),read(k);
            x^=las,k^=las;
            modify(root,x,select(root,x),-1);
            modify(root,x,k,1);
        }
        if (s[0]=='I'){
            read(x),read(k);
            x^=las,k^=las;
            insert(root,x-1,k,T);
            if (tmp!=T)
                rebuild(tmp),tmp=T;
        }
    }
    return 0;
}

线段树合并

#include <bits/stdc++.h>
#define N 70010
#define M 10000010
#define alpha 0.77
#define mid ((l+r)>>1)
#define K 70000
using namespace std;
int n,m,a[N],cnt;

template <class Aqua>
inline void read(Aqua &s){
    s=0; char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) s=s*10+c-'0',c=getchar();
}

struct seg{
    seg *ch[2];
    int s;
}t[M],*tail=t+1;
vector<int> res,v;
vector<seg*> q;

seg *newnode(){
    if (!res.size()){
        tail->ch[0]=tail->ch[1]=t;
        tail->s=0;
        return tail++;
    }
    else{
        seg *node=t+res.back();
        res.pop_back();
        node->ch[0]=node->ch[1]=t;
        node->s=0;
        return node;
    }
}

void raclaim(seg *&cur){
    if (cur==t) return;
    res.push_back(cur-t);
    raclaim(cur->ch[0]),raclaim(cur->ch[1]);
    cur=t;
}

void add(seg *&cur,int l,int r,int x,int d){
    if (cur==t) cur=newnode();
    cur->s+=d;
    if (l==r) return;
    if (x<=mid)
        add(cur->ch[0],l,mid,x,d);
    else
        add(cur->ch[1],mid+1,r,x,d);
    if (!cur->s)
        raclaim(cur),cur=t;
}

seg *merge(seg *a,seg *b,int l,int r){
    if (b==t) return a;
    if (a==t) a=newnode();
    if (l==r){
        a->s+=b->s;
        if (!a->s) raclaim(a);
        return a;
    }
    a->ch[0]=merge(a->ch[0],b->ch[0],l,mid);
    a->ch[1]=merge(a->ch[1],b->ch[1],mid+1,r);
    a->s=a->ch[0]->s+a->ch[1]->s;
    if (!a->s) raclaim(a);
    return a;
}

struct tree{
    tree *ch[2],*fa;
    seg *root; int size,x;
}T[N],*root=T,*tail_=T+1,*tmp=T,*b[N];

tree *newnode_(){
    tail_->ch[0]=tail_->ch[1]=tail_->fa=T;
    tail_->size=1; tail_->root=t;
    return tail_++;
}

void build(tree *&cur,int l,int r,tree *fa){
    if (l>r){
        cur=T; return;
    }
    cur=b[mid]; cur->x=a[mid]; cur->fa=fa;
    add(cur->root,0,K,a[mid],1);
    if (l==r){
        cur->size=1; cur->ch[0]=cur->ch[1]=T;
        return;
    }
    build(cur->ch[0],l,mid-1,cur);
    build(cur->ch[1],mid+1,r,cur);
    cur->size=cur->ch[0]->size+cur->ch[1]->size+1;
    cur->root=merge(cur->root,cur->ch[0]->root,0,K);
    cur->root=merge(cur->root,cur->ch[1]->root,0,K);
}

int select(tree *cur,int k){
    return (cur->ch[0]->size+1==k?cur->x:(cur->ch[0]->size>=k?select(cur->ch[0],k):select(cur->ch[1],k-cur->ch[0]->size-1)));
}

void modify(tree *cur,int k,int x,int d){
    add(cur->root,0,K,x,d);
    if (cur->ch[0]->size+1==k){
        cur->x=x; return;
    }
    else
        if (cur->ch[0]->size>=k)
            modify(cur->ch[0],k,x,d);
        else
            modify(cur->ch[1],k-cur->ch[0]->size-1,x,d);
}

void insert(tree *&cur,int k,int x,tree *fa){
    if (cur==T){
        cur=newnode_();
        cur->x=x; cur->fa=fa;
        add(cur->root,0,K,x,1);
        return;
    }
    add(cur->root,0,K,x,1);
    cur->size++;
    if (cur->ch[0]->size+1>k)
        insert(cur->ch[0],k,x,cur);
    else
        insert(cur->ch[1],k-cur->ch[0]->size-1,x,cur);
    if (max(cur->ch[0]->size,cur->ch[1]->size)>cur->size*alpha)
        tmp=cur;
}

void query(tree *cur,int l,int r,int L,int R){
    if (l>r) return;
    if (L<=l && r<=R){
        q.push_back(cur->root);
        return;
    }
    int Mid=l+cur->ch[0]->size;
    if (Mid>L)
        query(cur->ch[0],l,Mid-1,L,R);
    if (Mid>=L && Mid<=R)
        v.push_back(cur->x);
    if (Mid<R)
        query(cur->ch[1],Mid+1,r,L,R);
}

int Query(int l,int r,int k){
    q.clear(); v.clear();
    query(root,1,root->size,l,r);
    int s=0,x;
    for (l=0,r=K;l<r;s=0){
        for (int i=0;i<q.size();i++)
            s+=q[i]->ch[0]->s;
        for (int i=0;i<v.size();i++)
            if (v[i]>=l && v[i]<=mid)
                s++;
        if (s>=k)
            r=mid,x=0;
        else
            k-=s,l=mid+1,x=1;
        for (int i=0;i<q.size();i++)
            q[i]=q[i]->ch[x];
    }
    return l;
}

void dfs(tree *cur){
    if (cur==T) return;
    dfs(cur->ch[0]);
    a[++cnt]=cur->x,b[cnt]=cur;
    dfs(cur->ch[1]);
    raclaim(cur->root);
}

void rebuild(tree *cur){
    cnt=0; dfs(cur);
    tree *fa=cur->fa;
    if (fa==T)
        build(root,1,cnt,T);
    else
        build(fa->ch[(fa->ch[0]==cur)?0:1],1,cnt,fa);
}

int main(){
    read(n);
    for (int i=1;i<=n;i++)
        read(a[i]),b[i]=newnode_();
    T->size=0; T->root=t;
    t->ch[0]=t->ch[1]=t; t->s=0;
    build(root,1,n,T);
    read(m);
    char s[10]; int x,y,k,las=0;
    for (int i=1;i<=m;i++){
        scanf("%s",s);
        if (s[0]=='Q'){
            read(x),read(y),read(k);
            x^=las,y^=las,k^=las;
            printf("%d\n",las=Query(x,y,k));
        }
        if (s[0]=='M'){
            read(x),read(k);
            x^=las,k^=las;
            modify(root,x,select(root,x),-1);
            modify(root,x,k,1);
        }
        if (s[0]=='I'){
            read(x),read(k);
            x^=las,k^=las;
            insert(root,x-1,k,T);
            if (tmp!=T)
                rebuild(tmp),tmp=T;
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值