题目:

Description

您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
1.查询k在区间内的排名
2.查询区间内排名为k的值
3.修改某一位值上的数值
4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)
5.查询k在区间内的后继(后继定义为大于x,且最小的数)

Input

第一行两个数 n,m 表示长度为n的有序序列和m个操作
第二行有n个数,表示有序序列
下面有m行,opt表示操作标号
若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间[l,r]的排名
若opt=2 则为操作2,之后有三个数l,r,k 表示查询区间[l,r]内排名为k的数
若opt=3 则为操作3,之后有两个数pos,k 表示将pos位置的数修改为k
若opt=4 则为操作4,之后有三个数l,r,k 表示查询区间[l,r]内k的前驱
若opt=5 则为操作5,之后有三个数l,r,k 表示查询区间[l,r]内k的后继

Output

对于操作1,2,4,5各输出一行,表示查询结果

Sample Input

9 6
4 2 2 1 9 4 0 1 1
2 1 4 3
3 4 10
2 1 4 3
1 2 5 9
4 3 9 5
5 2 8 5

Sample Output

2
4
3
4
9

HINT

1.n和m的数据范围:n,m<=50000

2.序列中每个数的数据范围:[0,1e8]

3.虽然原题没有,但事实上5操作的k可能为负数

题解:

哎···这道题充分证明了我的代码能力和专注力是tm有多弱····

调了一个早上的代码···终于发现错哪里了····只是因为update里面的=写成了+=···

第一我打的时候打错了···第二我调的时候竟然没有看到这一点···我勒个大艹···

然后一个上午的时间就荒废在了这一个等号里···

下次打的时候我tm一定要注意细节了···不要以为打得顺手就打得正确···

题解的话···我在找标称对拍的时候惊讶的发现网上的一个小姐姐竟然和我写得几乎一模一样·····这里就引用她的吧(其实我splay的版基本都是看她的···)%%%%%%Clove_unique

线段树套splay,简单地说就是线段树的每一个节点都吊着一颗splay,表示的是线段树当前节点所表示的区间的点,按权值排序。 
  Q1:线段树常规查询区间,每一次统计小于k的点的个数再相加。 
  Q2:这个是最麻烦也是最精妙的一问,解决方法是二分答案,每二分到一个答案查询一下这个答案在这个区间内的排名,如果排名等于k+1的话返回它的pre即可。注意这里二分满   足条件之后不用查询pre,答案直接为head-1,可以证明head-1一定在序列中。 
  Q3:相当于线段树的点修改,在splay中删除再插入即可。 
  Q4:线段树常规查询区间,每一次找区间内比k小的最大的数,然后取max 
  Q5:类似于Q4,每一次找区间内比k大的最小的数,然后取min

自己再解释一下Q2的操作吧···询问的是排名为k的数···我们先找出第一个大于至少k的数最小的数x··如果是等于,那么此时left-1肯定是答案(最后right会等于left),如果是大于多于   k个数量的数··那么  想当于是x大于x-1,而x-1又大于少于k个数量的数···这种情况下x-1肯定是有重复的个数的,在连续的x-1中的某一x-1肯定刚好大于等于k个数量的数···那么x-1,即   left-1就是答案····如果x是大于等于k个数量的数,显然x-1是答案

当然这道题套treap会快太多···然而我并不想转treap···指针写起来太麻烦····

另外这道题如果怕爆空间可以回收节点·····然而我懒得写了···

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N=4e6+;
int root[N],son[N][],father[N],key[N],size[N],tot,n,m,num[],maxx=,cnt[N];
const int inf=1e9;
inline int R()
{
char c;int f=,i=;
for(c=getchar();(c<''||c>'')&&c!='-';c=getchar());
if(c=='-') c=getchar(),i=-;
for(;c<=''&&c>='';c=getchar())
f=(f<<)+(f<<)+c-'';
return f*i;
}
inline void clear(int now)
{
if(!now) return;
cnt[now]=son[now][]=son[now][]=father[now]=size[now]=;key[N]=;
}
inline void update(int now)
{
if(!now) return;
size[now]=cnt[now]+(son[now][]?size[son[now][]]:)+(son[now][]?size[son[now][]]:);
}
inline int get(int now){return son[father[now]][]==now;}
inline void rotate(int now)
{
int fa=father[now],ofa=father[fa],which=get(now);
son[fa][which]=son[now][which^],father[son[fa][which]]=fa;
son[now][which^]=fa,father[fa]=now,father[now]=ofa;
if(ofa) son[ofa][son[ofa][]==fa]=now;
update(fa),update(now);
}
inline void splay(int k,int now)
{
while(father[now])
{
if(father[father[now]])
rotate(get(now)==get(father[now])?father[now]:now);
rotate(now);
}
root[k]=now;
}
inline int findkth(int k,int v) //查询排名
{
int now=root[k],ans=;
while(true)
{
if(!now) return ans;
if(v==key[now]) return (son[now][]?size[son[now][]]:)+ans;
else if(v>key[now])
{
ans+=(son[now][]?size[son[now][]]:)+cnt[now];
now=son[now][];
}
else if(v<key[now]) now=son[now][];
}
}
inline int findpos(int k,int v) //找到位置
{
int now=root[k];
while(true)
{
if(v==key[now]) return now;
else if(v<key[now]) now=son[now][];
else now=son[now][];
}
}
inline void insert(int k,int v)
{
int now=root[k],last=;
while(true)
{
if(!now)
{
now=++tot;father[now]=last;key[now]=v;size[now]=cnt[now]=;son[now][]=son[now][]=;
if(!root[k]) root[k]=now;
else
{
son[last][v>key[last]]=now;
update(last);
splay(k,now);
}
break;
}
else if(v==key[now])
{
cnt[now]++;update(now);update(last);
splay(k,now);
break;
}
last=now;now=son[now][v>key[now]];
}
}
inline int pre(int k)
{
int now=son[root[k]][];
while(son[now][]) now=son[now][];
return now;
}
inline void del(int k,int v)
{
int now=findpos(k,v);
splay(k,now);
if(cnt[root[k]]>) {cnt[root[k]]--,update(root[k]);return;}
else if(!son[root[k]][]&&!son[root[k]][]){clear(root[k]);root[k]=;return;}
else if(!son[root[k]][])
{
int oldroot=root[k];root[k]=son[root[k]][];father[root[k]]=;
clear(oldroot);return;
}
else if(!son[root[k]][])
{
int oldroot=root[k];root[k]=son[root[k]][];father[root[k]]=;
clear(oldroot);return;
}
else
{
int oldroot=root[k];
int leftbig=pre(k);splay(k,leftbig);
son[root[k]][]=son[oldroot][];
father[son[root[k]][]]=root[k];
update(root[k]);clear(oldroot);return;
}
}
inline int findpre(int k,int v)
{
int now=root[k],ans=;
while(now)
{
if(key[now]<v)
{
if(ans<key[now]) ans=key[now];
now=son[now][];
}
else now=son[now][];
}
return ans;
}
inline int findnxt(int k,int v)
{
int now=root[k],ans=inf;
while(now)
{
if(key[now]>v)
{
if(ans>key[now]) ans=key[now];
now=son[now][];
}
else now=son[now][];
}
return ans;
}
//---------------------------------------------splay
inline void seginsert(int k,int l,int r,int x,int v)
{
insert(k,v);
if(l==r) return;
int mid=(l+r)/;
if(x<=mid) seginsert(k*,l,mid,x,v);
else seginsert(k*+,mid+,r,x,v);
return;
}
inline int segfindkth(int k,int l,int r,int x,int y,int v)
{
if(l>=x&&r<=y) return findkth(k,v);
int mid=(l+r)/;int temp=;
if(x<=mid) temp+=segfindkth(k*,l,mid,x,y,v);
if(y>mid) temp+=segfindkth(k*+,mid+,r,x,y,v);
return temp;
}
inline void segmodify(int k,int l,int r,int x,int v)
{
del(k,num[x]);
insert(k,v);
if(l==r) return;
int mid=(l+r)/;
if(x<=mid) segmodify(k*,l,mid,x,v);
else segmodify(k*+,mid+,r,x,v);
}
inline int segpre(int k,int l,int r,int x,int y,int v)
{
if(l>=x&&r<=y) return findpre(k,v);
int mid=(l+r)/;int temp=;
if(x<=mid) temp=max(temp,segpre(k*,l,mid,x,y,v));
if(y>mid) temp=max(temp,segpre(k*+,mid+,r,x,y,v));
return temp;
}
inline int segnxt(int k,int l,int r,int x,int y,int v)
{
if(l>=x&&r<=y) return findnxt(k,v);
int mid=(l+r)/;int temp=inf;
if(x<=mid) temp=min(temp,segnxt(k*,l,mid,x,y,v));
if(y>mid) temp=min(temp,segnxt(k*+,mid+,r,x,y,v));
return temp;
}
inline void dfs(int now)
{
cout<<key[now]<<" ";
if(son[now][]) dfs(son[now][]);
if(son[now][]) dfs(son[now][]);
}
int main()
{
n=R(),m=R();int op,a,b,c;
for(int i=;i<=n;i++) a=R(),seginsert(,,n,i,a),num[i]=a,maxx=max(maxx,num[i]);
while(m--)
{
op=R();
if(op==) {a=R(),b=R(),c=R();printf("%d\n",segfindkth(,,n,a,b,c)+);}
else if(op==)
{
a=R(),b=R(),c=R();
int le=,ri=maxx+;int ans=;
while(le!=ri)
{
int mid=(le+ri)/;
int temp=segfindkth(,,n,a,b,mid);
if(temp<c) le=mid+;
else ri=mid;
}
printf("%d\n",le-);
}
else if(op==) {a=R(),b=R();segmodify(,,n,a,b);num[a]=b;maxx=max(maxx,b);}
else if(op==) {a=R(),b=R(),c=R();printf("%d\n",segpre(,,n,a,b,c));}
else if(op==) {a=R(),b=R(),c=R();printf("%d\n",segnxt(,,n,a,b,c));}
}
return ;
}

刷题总结——二逼平衡树(bzoj3224线段树套splay)的更多相关文章

  1. BZOJ 3196 Tyvj 1730 二逼平衡树:线段树套splay

    传送门 题意 给你一个长度为 $ n $ 有序数列 $ a $ ,进行 $ m $ 次操作,操作有如下几种: 查询 $ k $ 在区间 $ [l,r] $ 内的排名 查询区间 $ [l,r] $ 内排 ...

  2. bzoj 3196 Tyvj 1730 二逼平衡树【线段树 套 splay】

    四舍五入就是个暴力. 对于线段树的每个区间都开一棵按权值排序的splay 对于第二个操作,二分一下,每次查询mid的排名,复杂度 $ O(nlog(n)^{3}) $ 其余的操作都是$ O(nlog( ...

  3. [BZOJ3196] [Tyvj1730] 二逼平衡树(线段树 套 Splay)

    传送门 至少BZOJ过了,其他的直接弃. 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的 ...

  4. bzoj 3196 Tyvj 1730 二逼平衡树(线段树套名次树)

    3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1807  Solved: 772[Submit][Stat ...

  5. bzoj 3196/ Tyvj 1730 二逼平衡树 (线段树套平衡树)

    3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description ...

  6. BZOJ3196 二逼平衡树 【线段树套平衡树】

    题目 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱 ...

  7. BZOJ3196 二逼平衡树 ZKW线段树套vector(滑稽)

    我实在是不想再打一遍树状数组套替罪羊树了... 然后在普通平衡树瞎逛的时候找到了以前看过vector题解 于是我想:为啥不把平衡树换成vector呢??? 然后我又去学了一下ZKW线段树 就用ZKW线 ...

  8. 【bzoj3196-二逼平衡树】线段树套平衡树

    http://acm.hust.edu.cn/vjudge/problem/42297 [题目描述] 写一种数据结构,来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间 ...

  9. 【BZOJ 3196】二逼平衡树 线段树套splay 模板题

    我写的是线段树套splay,网上很多人写的都是套treap,然而本蒟蒻并不会treap 奉上sth神犇的模板: //bzoj3196 二逼平衡树,支持修改某个点的值,查询区间第k小值,查询区间某个值排 ...

随机推荐

  1. CF Gym 100637F The Pool for Lucky Ones

    题意:给你一串非负整数,可以将一个非零数减1,加到相邻的数字上,要使其中所有最大数字的和最小. 题解:模拟可以过.也可以分析,可以要减少最大数字和,如果最大数字出现大于等于3次,可以把最大数字加一,或 ...

  2. uva806 Spatial Structures 空间结构 (黑白图像的四分树表示)

    input 8 00000000 00000000 00001111 00001111 00011111 00111111 00111100 00111000 -8 9 14 17 22 23 44 ...

  3. 【转】Deactivating your reflector

    原文:http://blog.csdn.net/cxwl3sxl/article/details/8072195 背景: 因为想破解一个.net写的程序,需要在visual studio 2010中使 ...

  4. ajax的序列化表单提交

    通过传统的 form 表单提交的方式上传文件 ? 1 2 3 4 <form id="uploadForm" action="" method=" ...

  5. ssh整合思想 Spring与Hibernate的整合 项目在服务器启动则自动创建数据库表

    Spring整合Hibernate Spring的Web项目中,web.xml文件会自动加载,以出现欢迎首页.也可以在这个文件中对Spring的配置文件进行监听,自启动配置文件, 以及之前Struts ...

  6. 浅谈JavaScript中的正则表达式(适用初学者观看)

    浅谈JavaScript中的正则表达式 1.什么是正则表达式(RegExp)? 官方定义: 正则表达式是一种特殊的字符串模式,用于匹配一组字符串,就好比用模具做产品,而正则就是这个模具,定义一种规则去 ...

  7. 01 Web框架介绍

    一.Web框架本质 所有的web应用程序本质上都是socket,用户的浏览器其实就是一个socket客户端. python中常用的web框架有: Django Flask web.py WSGI(we ...

  8. python 爬取知乎图片

    先上完整代码 import requests import time import datetime import os import json import uuid from pyquery im ...

  9. 点击tr实现选择checkbox功能,点击checkobx的时候阻止冒泡事件, jquery给checkbox添加checked属性或去掉checked属性不能使checkobx改变状态

    给tr添加点击事件,使用find方法查找tr下的所有层级的元素,children只查找下一层级的元素,所以使用find.find的返回值为jquery对象,在这个项目中不知道为什么使用jquery给c ...

  10. ASP( VBScript ) 解析 JSON

    <script language="jscript" runat="server"> Array.prototype.get = function( ...