【BZOJ3065】带插入区间K小值

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组数据。

题解:对于本题,直接外层替罪羊树+内层权值线段树即可,具体地:

修改:先查一下原来的权值,将替罪羊树的路径上所有点的权值线段树中删去原来的权值,再加上新的权值即可。
加入:直接向再路径上的所有点的权值线段树加入这个权值即可,再判一下重构。(本人写丑了,如果多个子树都失衡了,那么只重构最大的子树即可)
查询:跟树状数组套主席树的姿势差不多,我们先在替罪羊树中将这些区间对应的log棵权值线段树(以及单点)都提取出来,然后一起二分即可。

本题需要动态开点,数组开到2000w差不多~

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
const int N=70000;
const int maxn=70010;
struct sag
{
int ls,rs,siz;
}s[20000005];
struct bst
{
int ls,rs,siz,rt,val;
}t[maxn];
int p[maxn],pp[maxn],ans,root,n,m;
char str[10];
queue<int> q;
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
void updata(int l,int r,int &x,int a,int b)
{
if(!x) x=q.front(),q.pop();
s[x].siz+=b;
if(l==r) return ;
int mid=(l+r)>>1;
if(a<=mid) updata(l,mid,s[x].ls,a,b);
else updata(mid+1,r,s[x].rs,a,b);
}
int build(int l,int r)
{
if(l>r) return 0;
int mid=(l+r)>>1,x=p[mid],i;
t[x].siz=r-l+1;
t[x].ls=build(l,mid-1),t[x].rs=build(mid+1,r);
for(i=l;i<=r;i++) updata(0,N,t[x].rt,t[p[i]].val,1);
return x;
}
void del(int &x)
{
if(!x) return ;
del(s[x].ls),del(s[x].rs),s[x].siz=0,q.push(x),x=0;
}
void dfs(int x)
{
if(!x) return ;
dfs(t[x].ls),p[++p[0]]=x,dfs(t[x].rs),t[x].ls=t[x].rs=t[x].siz=0;
del(t[x].rt);
}
void insert(int &x,int y)
{
if(!x)
{
x=n,t[x].siz=1,t[x].ls=t[x].rs=0,updata(0,N,t[x].rt,t[x].val,1);
return ;
}
t[x].siz++,updata(0,N,t[x].rt,t[n].val,1);
if(y>=t[t[x].ls].siz+1) insert(t[x].rs,y-t[t[x].ls].siz-1);
else insert(t[x].ls,y);
if(t[x].siz>=10&&(t[t[x].ls].siz*4<t[t[x].rs].siz*3||t[t[x].ls].siz*3>t[t[x].rs].siz*4))
p[0]=0,dfs(x),x=build(1,p[0]);
}
int getval(int x,int y)
{
if(y>t[t[x].ls].siz+1) return getval(t[x].rs,y-t[t[x].ls].siz-1);
if(y<=t[t[x].ls].siz) return getval(t[x].ls,y);
return t[x].val;
}
void modify(int x,int y,int a,int b)
{
updata(0,N,t[x].rt,a,-1),updata(0,N,t[x].rt,b,1);
if(y>t[t[x].ls].siz+1) modify(t[x].rs,y-t[t[x].ls].siz-1,a,b);
else if(y<=t[t[x].ls].siz) modify(t[x].ls,y,a,b);
else t[x].val=b;
}
void find(int x,int a,int b)
{
if(a>b) return ;
if(a==1&&b==t[x].siz)
{
p[++p[0]]=t[x].rt;
return ;
}
if(b<=t[t[x].ls].siz) find(t[x].ls,a,b);
else if(a>t[t[x].ls].siz+1) find(t[x].rs,a-t[t[x].ls].siz-1,b-t[t[x].ls].siz-1);
else find(t[x].ls,a,t[t[x].ls].siz),pp[++pp[0]]=t[x].val,find(t[x].rs,1,b-t[t[x].ls].siz-1);
}
int query(int l,int r,int x)
{
if(l==r) return l;
int sl=0,mid=(l+r)>>1,i;
for(i=1;i<=p[0];i++) sl+=s[s[p[i]].ls].siz;
for(i=1;i<=pp[0];i++) sl+=(pp[i]>=l&&pp[i]<=mid);
if(x>sl)
{
for(i=1;i<=p[0];i++) p[i]=s[p[i]].rs;
return query(mid+1,r,x-sl);
}
for(i=1;i<=p[0];i++) p[i]=s[p[i]].ls;
return query(l,mid,x);
}
int main()
{
n=rd();
int i,a,b,c;
for(i=1;i<=20000000;i++) q.push(i);
for(i=1;i<=n;i++) t[i].val=rd(),p[i]=i;
root=build(1,n);
m=rd();
for(i=1;i<=m;i++)
{
scanf("%s",str),a=rd()^ans,b=rd()^ans;
if(str[0]=='Q')
{
c=rd()^ans,p[0]=pp[0]=0;
find(root,a,b);
ans=query(0,N,c);
printf("%d\n",ans);
}
if(str[0]=='M')
{
c=getval(root,a),modify(root,a,c,b);
}
if(str[0]=='I')
{
t[++n].val=b,insert(root,a-1);
}
}
return 0;
}//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

【BZOJ3065】带插入区间K小值 替罪羊树+权值线段树的更多相关文章

  1. [BZOJ3065]带插入区间K小值 解题报告 替罪羊树+值域线段树

    刚了一天的题终于切掉了,数据结构题的代码真**难调,这是我做过的第一道树套树题,做完后感觉对树套树都有阴影了......下面写一下做题记录. Portal Gun:[BZOJ3065]带插入区间k小值 ...

  2. BZOJ3065 带插入区间K小值 || 洛谷P4278

    这是一道让我崩溃的题...... 然鹅洛谷上时限被改然后只有20分......好像所有人都被卡了(雾) 由于替罪羊树不是依靠旋转操作而是依靠暴力重构的方式维护树的平衡,所以我们可以考虑使用替罪羊树套区 ...

  3. 【函数式权值分块】【块状链表】bzoj3065 带插入区间K小值

    显然是块状链表的经典题.但是经典做法的复杂度是O(n*sqrt(n)*log^2(n))的,出题人明确说了会卡掉. 于是我们考虑每个块内记录前n个块的权值分块. 查询的时候差分什么的,复杂度就是O(n ...

  4. bzoj3065: 带插入区间K小值

    无聊来写了下 一开始发现树高是O(n)的,然后就MLE了,进去看了下发现没有重构! 看了半天发现调用错了函数 然后进去又发现不满足sz = ch[0]->sz + ch[1]->sz + ...

  5. bzoj 3065: 带插入区间K小值 替罪羊树 && AC300

    3065: 带插入区间K小值 Time Limit: 60 Sec  Memory Limit: 512 MBSubmit: 1062  Solved: 253[Submit][Status] Des ...

  6. 【题解】BZOJ 3065: 带插入区间K小值——替罪羊树套线段树

    题目传送门 题解 orz vfk的题解 3065: 带插入区间K小值 系列题解 一 二 三 四 惨 一开始用了一种空间常数很大的方法,每次重构的时候merge两颗线段树,然后无限RE(其实是MLE). ...

  7. 3065: 带插入区间K小值_树套树_替罪羊树_权值线段树

    经过周六一天,周一3个小时的晚自习,周二2个小时的疯狂debug,终于凭借自己切掉了这道树套树题. Code: #include <cstdio> #include <algorit ...

  8. BZOJ 3065 带插入区间K小值(sag套线段树)

    3065: 带插入区间K小值 Time Limit: 60 Sec  Memory Limit: 512 MBSubmit: 4696  Solved: 1527[Submit][Status][Di ...

  9. 【学习笔记】浅析平衡树套线段树 & 带插入区间K小值

    常见的树套树 一般来说,在嵌套数据结构中,线段树多被作为外层结构使用. 但线段树毕竟是 静态 的结构,导致了一些不便. 下面是一个难以维护的例子: 带插入区间 \(k\) 小值问题 来源:Luogu ...

随机推荐

  1. android 集成友盟分享之后,想自定义分享面板的看过来

    第一种情况 首先上传一张默认的友盟分享的效果图 看起来还不错,但是总是有这样那样的原因,需要我们对默认效果做出一些改变. 第二种情况 如果你想做出下面的效果: 或者这样的效果 : 总之上面的效果总是在 ...

  2. redis入门与集群部署

    redis入门 redis入门级教程非常多,如http://www.runoob.com/redis/redis-backup.html,作为入门其实已经十分详细了,主要学习内容有如下几个方面吧 1. ...

  3. workflow engine Ruote 安装

    今天在安装gem安装Ruote的过程中遇到问题,改用bundle安装: steven@steven-Latitude-D630:/usr$ sudo mkdir bundel [sudo] passw ...

  4. Jenkins连接git时出现“Failed to connect to repository : Command ... HEAD" returned status code 128:”的问题解决

    网上说的解决方法如下: 其实生成ssh时不应该使用当前用户去生成ssh,而是使用jenkins这个用户去生成ssh,然后再去git服务器上配置你生成key,最后再jenkins上配置返回给你的key. ...

  5. 巧用chrome开发者工具

    说明:截图中的Chrome版本为52,不同版本可能略有区别. 常用设置 开发时消除静态资源缓存不能立刻更新的困扰,勾选Disable cache即可 切换颜色显示格式 修改默认颜色显示格式,在Sett ...

  6. 代码统计利器--CLOC

    MAC下安装命令:$ brew install cloc 其他的linux安装 $ aptitude install cloc 使用方法.到目录下运行: $ cloc . The default ou ...

  7. DB2 SQL Error: SQLCODE=-805, SQLSTATE=51002 解决方法

    在操作大量数据时如果发生这种错误,说明不是db2 使用的 package没有绑定,而是 因为资源未释放,导致可以使用此package的资源不足,致使不能连接资源. 在程序中,对PreparedStat ...

  8. 【2048小游戏】——原生js爬坑之遍历算法显示二维数组内容

    引言:做2048小游戏会将横纵方向的数字内容,存储在一个二维数组中,要将这个二维数组中的内容显示在页面上,就一定要用遍历算法来实现了. 一.二维数组存储    首先考虑用二维数组存储所有行数,列数   ...

  9. 2016.7.12 在navicat中用sql语句建表

    参考资料: http://jingyan.baidu.com/article/f0e83a25a8c4b022e5910116.html 即新建query,然后run. (1)点击要新建表的位置,选择 ...

  10. 根据DatabaseMetaData确定数据库类型

    根据DatabaseMetaData确定数据库类型 DataSource dataSource = dataSourceTransactionManager.getDataSource(); conn ...