bzoj 3065: 带插入区间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 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
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组数据。
我写的是分块


#include<cmath>
#include<cstdio>
#include<algorithm>
#define lla la;
using namespace std;
int read_p,read_ca;
inline int read(){
read_p=;read_ca=getchar();
while(read_ca<''||read_ca>'') read_ca=getchar();
while(read_ca>=''&&read_ca<='') read_p=read_p*+read_ca-,read_ca=getchar();
return read_p;
}
int n,m,a[][],b,num,la=,s[],k[][],ne[];
char ch[];
int i,j,x,c,l,r,lc,rc,li,ri;
inline bool cmp(int a,int b){
return a<b;
}
inline int que(int i,int x){
int l=,r=s[i]-,mid;
while (l<r){
mid=(l+r+)>>;
if (k[i][mid]>=x) r=mid-;else l=mid;
}
if (k[i][l]<x) l++;
return l;
}
inline int ask(){
l=read();r=read();x=read();
l^=lla;r^=lla;x^=lla;
lc=;rc=;
for (li=;li!=-;li=ne[li])
if ((lc+=s[li])>=l) break;
lc=l-lc+s[li]-;
for (ri=;ri!=-;ri=ne[ri])
if ((rc+=s[ri])>=r) break;
rc=r-rc+s[ri]-;
int ll=,rr=,mid,nu;
while (ll<rr){
mid=(ll+rr+)>>;nu=;
if (li!=ri){
for (i=ne[li];i!=ri;i=ne[i]) nu+=que(i,mid);
for (i=lc;i<s[li];i++) if (a[li][i]<mid) nu++;
for (i=;i<=rc;i++) if (a[ri][i]<mid) nu++;
}else for (i=lc;i<=rc;i++) if (a[li][i]<mid) nu++;
if (nu>=x) rr=mid-;else ll=mid;
}
return ll;
}
inline void change(){
x=read();c=read();
x^=lla;c^=lla;
l=;
for (i=;i!=-;i=ne[i])
if ((l+=s[i])>=x) break;
x=x-l+s[i]-;
for (j=;j<s[i];j++) if (k[i][j]==a[i][x]) break;
k[i][j]=a[i][x]=c;
while (j&&(k[i][j-]>k[i][j])) swap(k[i][j-],k[i][j]),j--;
while ((j<s[i]-)&&(k[i][j]>k[i][j+])) swap(k[i][j+],k[i][j]),j++;
}
inline void in(){
x=read();c=read();
x^=lla;c^=lla;
l=;
for (i=;i!=-;i=ne[i]){
l+=s[i];
if (l>=x||ne[i]==-) break;
}
x-=l-s[i]+;
for (j=s[i];j>x;j--) a[i][j]=a[i][j-];
s[i]++;a[i][x]=c;
if (s[i]==*b){
s[num]=b;
s[i]=b;
ne[num]=ne[i];
ne[i]=num;
for (j=;j<b;j++) k[num][j]=a[num][j]=a[i][b+j],k[i][j]=a[i][j];
sort(k[i],k[i]+b,cmp);sort(k[num],k[num]+b,cmp);
num++;
}else{
for (j=;j<s[i]-;j++) if (c<k[i][j]) break;
l=j;
for (j=s[i]-;j>l;j--) k[i][j]=k[i][j-];
k[i][l]=c;
}
}
inline int max(int a,int b){return a>b?a:b;}
int main(){
n=read();
b=;
num=(n+b-)/b;
for (int i=;i<n;i++) k[i/b][i%b]=a[i/b][i%b]=read();
for (int i=;i<num-;i++) s[i]=b,ne[i]=i+;s[num-]=n-b*(num-);
ne[num-]=-;
for (int i=;i<num;i++) sort(k[i],k[i]+s[i],cmp);
m=read();
while(m--){
scanf("%s",ch);
if (ch[]=='Q') printf("%d\n",la=ask());else
if (ch[]=='M') change();else
in();
}
}
后来又写了块套线段树版本,慢了很多(45s)
#include<cmath>
#include<cstdio>
#include<algorithm>
#define lla la;
using namespace std;
int read_p,read_ca;
inline int read(){
read_p=;read_ca=getchar();
while(read_ca<''||read_ca>'') read_ca=getchar();
while(read_ca>=''&&read_ca<='') read_p=read_p*+read_ca-,read_ca=getchar();
return read_p;
}
struct tree{
int l,r,k;
}t[];
int n,m,a[][],b,num,nnu,nm=,la=,s[],ne[],xc[],mid,root[];
char ch[];
int i,j,x,c,l,r,lc,rc,li,ri;
const int MA=;
inline bool cmp(int a,int b){
return a<b;
}
inline void in(int &p,int x){
if (!p) p=++nm,t[nm].l=t[nm].r=t[nm].k=;
int o=p;
int l=,r=MA,mid;
while(l<r){
t[o].k++;
mid=l+r>>;
if (x<=mid){
if (!t[o].l) t[o].l=++nm,t[nm].l=t[nm].r=t[nm].k=;
o=t[o].l;
r=mid;
}else{
if (!t[o].r) t[o].r=++nm,t[nm].l=t[nm].r=t[nm].k=;
o=t[o].r;
l=mid+;
}
}
t[o].k++;
}
inline void del(int p,int x){
int l=,r=MA,mid;
while(l<r){
t[p].k--;
mid=l+r>>;
if (x<=mid) p=t[p].l,r=mid;else p=t[p].r,l=mid+;
}
t[p].k--;
}
inline int ask(){
l=read();r=read();x=read();
l^=lla;r^=lla;x^=lla;
lc=;rc=;
for (li=;li!=-;li=ne[li])
if ((lc+=s[li])>=l) break;
lc=l-lc+s[li]-;
for (ri=;ri!=-;ri=ne[ri])
if ((rc+=s[ri])>=r) break;
rc=r-rc+s[ri]-;
int ll=,rr=,mid,nu,rt=;
nnu=nm;
for (i=;i<num;i++) xc[i]=root[i];
if (li!=ri){
for (i=lc;i<s[li];i++) in(rt,a[li][i]);
for (i=;i<=rc;i++) in(rt,a[ri][i]);
}else for (i=lc;i<=rc;i++) in(rt,a[li][i]);
int k;
l=;r=MA;
while(l<r){
mid=l+r>>;k=;
if (li!=ri)for (int i=ne[li];i!=ri;i=ne[i]) k+=t[t[xc[i]].l].k;k+=t[t[rt].l].k;
if (k>=x){
if (li!=ri)for (int i=ne[li];i!=ri;i=ne[i]) xc[i]=t[xc[i]].l;rt=t[rt].l;
r=mid;
}else{
x-=k;
if (li!=ri)for (int i=ne[li];i!=ri;i=ne[i]) xc[i]=t[xc[i]].r;rt=t[rt].r;
l=mid+;
}
}
nm=nnu;
return l;
}
inline void change(){
x=read();c=read();
x^=lla;c^=lla;
l=;
for (i=;i!=-;i=ne[i])
if ((l+=s[i])>=x) break;
x=x-l+s[i]-;
del(root[i],a[i][x]);
a[i][x]=c;
in(root[i],c);
}
inline void in(){
x=read();c=read();
x^=lla;c^=lla;
l=;
for (i=;i!=-;i=ne[i]){
l+=s[i];
if (l>=x||ne[i]==-) break;
}
x-=l-s[i]+;
for (j=s[i];j>x;j--) a[i][j]=a[i][j-];
s[i]++;a[i][x]=c;
in(root[i],c);
if (s[i]==*b){
s[i]=s[num]=b;
root[num]=;
for (j=;j<b;j++) a[num][j]=a[i][j+b];
for (j=;j<b;j++) del(root[i],a[num][j]),in(root[num],a[num][j]);
ne[num]=ne[i];ne[i]=num;
num++;
}
}
inline int max(int a,int b){return a>b?a:b;}
int main(){
/*freopen("a.in","r",stdin);
freopen("a.out","w",stdout);*/
n=read();
b=;
num=(n+b-)/b;
for (int i=;i<n;i++) a[i/b][i%b]=read(),in(root[i/b],a[i/b][i%b]);
for (int i=;i<num-;i++) s[i]=b,ne[i]=i+;s[num-]=n-b*(num-);
ne[num-]=-;
m=read();
while(m--){
scanf("%s",ch);
if (ch[]=='Q') printf("%d\n",la=ask());else
if (ch[]=='M') change();else
in();
}
}
bzoj 3065: 带插入区间K小值(分块)的更多相关文章
- bzoj 3065: 带插入区间K小值 替罪羊树 && AC300
3065: 带插入区间K小值 Time Limit: 60 Sec Memory Limit: 512 MBSubmit: 1062 Solved: 253[Submit][Status] Des ...
- 【题解】BZOJ 3065: 带插入区间K小值——替罪羊树套线段树
题目传送门 题解 orz vfk的题解 3065: 带插入区间K小值 系列题解 一 二 三 四 惨 一开始用了一种空间常数很大的方法,每次重构的时候merge两颗线段树,然后无限RE(其实是MLE). ...
- BZOJ 3065 带插入区间K小值(sag套线段树)
3065: 带插入区间K小值 Time Limit: 60 Sec Memory Limit: 512 MBSubmit: 4696 Solved: 1527[Submit][Status][Di ...
- BZOJ 3065 带插入区间K小值
http://www.lydsy.com/JudgeOnline/problem.php?id=3065 思路:替罪羊树套权值线段树. 当替罪羊树某个子树大于某个比利(比例)时就暴力重构,本题时间复杂 ...
- BZOJ 3065 带插入区间K小值 (替罪羊树套线段树)
毒瘤题.参考抄自博客:hzwer 第一次写替罪羊树,完全是照着题解写的,发现这玩意儿好强啊,不用旋转每次都重构还能nlognnlognnlogn. 还有外面二分和里面线段树的值域一样,那么r = mi ...
- 3065: 带插入区间K小值_树套树_替罪羊树_权值线段树
经过周六一天,周一3个小时的晚自习,周二2个小时的疯狂debug,终于凭借自己切掉了这道树套树题. Code: #include <cstdio> #include <algorit ...
- 【BZOJ】3065: 带插入区间K小值
http://www.lydsy.com/JudgeOnline/problem.php?id=3065 题意:带插入.修改的区间k小值在线查询.(原序列n<=35000, 询问<=175 ...
- 「BZOJ3065」带插入区间K小值 [分块]
考虑分块,每个块都是用 链表 维护的,并保证 \(size\) 和分块相当. 我们考虑一下怎么去查询,很显然,可以对值域分块,单点修改,记录前缀和,完全ojbk了,对每个块维护一个 \(pre , p ...
- 【学习笔记】浅析平衡树套线段树 & 带插入区间K小值
常见的树套树 一般来说,在嵌套数据结构中,线段树多被作为外层结构使用. 但线段树毕竟是 静态 的结构,导致了一些不便. 下面是一个难以维护的例子: 带插入区间 \(k\) 小值问题 来源:Luogu ...
随机推荐
- 【HTML】HTML基础知识
<!DOCTYPE html>表示HTML5文档申明,不区别大小写,通常这么写. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 ...
- asp.net MVC分页
.Net MVC 分页代码,分页的关键就是在于这几个参数pageIndex ,recordCount,pageSize ,下面是张林的网站做的一个简单的分页代码 效果如图 public class ...
- Cat 客户端如何构建调用链消息树
场景 & 代码 Inner0 中的某方法调用了 Inner1,代码 Inner1的代码很简单, Cat通过一个线程本地变量来保存调用链的相关信息,其中核心的数据结构是消息树和操作栈.消息树用来 ...
- vmstat 命令详解
作用:vmstat 的含义为显示虚拟内存状态(virtual memor statics),但是它可以报告关于进程,内存,I/O 等系统整体运行状态 选项: -a 显示活动内页 -f 显示启动后创建的 ...
- linux 写U盘出现的问题
在写U盘的时候,报了这样的错,记录如下: umount /dev/sdb // 提示未挂载 mkfs.vfat /dev/sdb // device or resource busy umount / ...
- 7、正确的赚钱方式 - CEO之公司管理经验谈
创业者创办公司,最初的目的就是为了赚钱,而普通的员工来公司上班,为了生计,也是以赚钱为目的.今天我们就讲讲正确的赚钱方式. 一.去公司上班: 来公司上班是第一个主要的赚钱方式.不管是员工还是公司领导, ...
- leetcode — linked-list-cycle
/** * Source : https://oj.leetcode.com/problems/linked-list-cycle/ * * Given a linked list, determin ...
- ASP.NET MVC框架开发系列教程
本系列教程是自己在工作中使用到而记录的,如有错误之处,请给与指正 文章目录 MVC4 开篇 第一章 初识MVC4 第二章 下山遇虎(@helper) 第三章 Models模块属性详解 第四章 在MVC ...
- linux apache虚拟主机配置(基于ip,端口,域名)
配置环境: linux版本:Centos6.4 httpd版本: [root@centos64Study init.d]# pwd/etc/init.d[root@centos64Study init ...
- 自动化测试-Selenium家谱介绍
一.自动化测试定义 自动化测试是通工具录制或编写脚本的方式模拟手工测试的过程,通过回放或运行脚本来执行测试用例,从而代替人工对系统的功能进行验证. 二.什么样的项目适合做自动化测试 1.需求明确,不会 ...