bzoj3065 带插入区间K小值

http://www.elijahqi.win/2018/02/26/bzoj3065/
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组数据。

替罪羊树套权值线段树

替罪羊树是一种不用旋转的平衡树,若一棵子树的左或右子树大小超过其大小55%-80%则暴力重构这棵子树,以此来维护平衡性,每个结点的期望重构次数是logn,实现可以自己脑补一下

替罪羊树 也是平衡树 只不过每次不旋转 直接暴力重构 这题 我针对每个节点建一个权值线段树 然后每次做的时候log^2的往里面插入 但是 有时候会暴力重构所以插入复杂度log^3 每个权值线段树维护的是这个区间的一些信息 查询的时候我先把这段区间提取出来 然后类似主席树在线段树上二分即可 空间开不下 所以需要回收内存 这个就写的比较辛苦了

#include<queue>
#include<vector>
#include<cstdio>
#include<algorithm>
#define alpha 0.75
#define N 77000
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=gc();}
    while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int ans,cnt,num,id[N],lc[N],rc[N],rt[N],v[N],n,m,root;
struct node{
    int left,right,s;
}tree[10000000];
queue<int>rec;int top,*q[N];
inline int init(){
    if (rec.empty()) return ++cnt;int x=rec.front();
    rec.pop();return x;
}
inline void recycle(int &x){
    if (!x) return;rec.push(x);recycle(tree[x].left);
    recycle(tree[x].right);tree[x].s=0;x=0;
}
inline void insert1(int &x,int l,int r,int p,int vv){
    if (!x) x=init();tree[x].s+=vv;if(l==r) return;int mid=l+r>>1;
    if (p<=mid) insert1(tree[x].left,l,mid,p,vv);else insert1(tree[x].right,mid+1,r,p,vv);
    if (!tree[x].s) recycle(x);
}
inline void build(int &x,int l,int r){
    int mid=l+r>>1;x=id[mid];
    for (int i=l;i<=r;++i) insert1(rt[x],0,70000,v[id[i]],1);
    if (l<mid)build(lc[x],l,mid-1);if (r>mid)build(rc[x],mid+1,r);
}
inline int modify(int x,int p,int vv){
    insert1(rt[x],0,70000,vv,1);int sz=tree[rt[lc[x]]].s,tmp;
    if (p==sz+1) tmp=v[x],v[x]=vv;if (p<=sz) tmp=modify(lc[x],p,vv);
    if (p>sz+1) tmp=modify(rc[x],p-sz-1,vv);insert1(rt[x],0,70000,tmp,-1);return tmp;
}
inline void del(int &x){
    if (!x) return;recycle(rt[x]);
    del(lc[x]);id[++num]=x;del(rc[x]);x=0;
}
inline void rebuild(int &x){
    num=0;del(x);build(x,1,num);
}
inline void ins(int &x,int p,int vv){
    if (!x) {x=++n;v[x]=vv;insert1(rt[x],0,70000,vv,1);return;}insert1(rt[x],0,70000,vv,1);
    int sz=tree[rt[lc[x]]].s;if (p<=sz+1) {ins(lc[x],p,vv);
    if (tree[rt[x]].s*alpha<tree[rt[lc[x]]].s)q[++top]=&x;}else {
    ins(rc[x],p-sz-1,vv);if(tree[rt[x]].s*alpha<tree[rt[rc[x]]].s)q[++top]=&x;}
}
vector<int> a1,a;
inline void pre(int x,int l,int r){
    int sz=tree[rt[x]].s,szl=tree[rt[lc[x]]].s;
    if (l==1&&r==sz) {a.push_back(rt[x]);return;}
    if (r<=szl) {pre(lc[x],l,r);return;}if (l>szl+1) {pre(rc[x],l-szl-1,r-szl-1);return;}
    a1.push_back(v[x]);pre(lc[x],l,szl);pre(rc[x],1,r-szl-1);
}
inline void query(int l1,int r1,int p){
    pre(root,l1,r1);int l=0,r=70000;
    while(l<=r){
        if (l==r) break;int mid=l+r>>1,sum=0;
        for (int i=0;i<a.size();++i) sum+=tree[tree[a[i]].left].s;
        for (int i=0;i<a1.size();++i) sum+=(a1[i]<=mid&&a1[i]>=l);
        if (p<=sum){for (int i=0;i<a.size();++i) a[i]=tree[a[i]].left;r=mid;}
        else{for (int i=0;i<a.size();++i) a[i]=tree[a[i]].right;l=mid+1;p-=sum;}
    }ans=l;a.clear();a1.clear();printf("%d\n",ans);
}
inline void print(int x){
    if (lc[x]) print(lc[x]);
    printf("%d %d \n",v[x],tree[rt[x]].s);
    if (rc[x]) print(rc[x]);
} 
int main(){
    freopen("bzoj3065.in","r",stdin);
    n=read();for (int i=1;i<=n;++i) v[i]=read(),id[i]=i;
    build(root,1,n);m=read();
    while(m--){
        char ch=gc();while(ch!='Q'&&ch!='I'&&ch!='M') ch=gc();
        if (ch=='Q'){int x=read()^ans,y=read()^ans,k=read()^ans;query(x,y,k);}
        if (ch=='M'){int x=read()^ans,val=read()^ans;modify(root,x,val);}
        if (ch=='I'){int x=read()^ans,val=read()^ans;top=0;ins(root,x,val);if (top) rebuild(*q[top]);}
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值