BZOJ 3196 Tyvj 1730 二逼平衡树:线段树套splay
题意
给你一个长度为 $ n $ 有序数列 $ a $ ,进行 $ m $ 次操作,操作有如下几种:
- 查询 $ k $ 在区间 $ [l,r] $ 内的排名
- 查询区间 $ [l,r] $ 内排名为 $ k $ 的值
- 将 $ a[p] $ 修改为 $ k $
- 查询 $ k $ 在区间 $ [l,r] $ 内的前驱(前驱定义为小于 $ k $ ,且最大的数)
- 查询 $ k $ 在区间 $ [l,r] $ 内的后继(后继定义为大于 $ k $ ,且最小的数)
题解
线段树套splay。
先将 $ n $ 个数插入线段树:对于每个 $ a[i] $,将线段树上到位置 $ i $ 的叶子节点的路径上的所有splay插入元素 $ a[i] $ 。
操作1:区间 $ [l,r] $ 在线段树上对应了若干棵splay,将这些splay中小于 $ k $ 的元素个数累加,记为 $ sum $ ,$ sum+1 $ 即为答案。
操作2:二分这个元素的值,然后进行操作1得到当前rank,对应地调整答案。
操作3:将线段树上到位置 $ p $ 的叶子节点的路径上的所有splay删除 $ a[p] $ ,再插入 $ k $ ,然后更新 $ a[p] = k $ 。
操作4:将区间 $ [l,r] $ 对应的所有splay中查询到的 $ k $ 的前驱取 $ max $ 即可。
操作5:将区间 $ [l,r] $ 对应的所有splay中查询到的 $ k $ 的后继取 $ min $ 即可。
最后,纪念一下我用pbds加map封装的的假splay......QAQ
还有就是因为b站g++版本太老,null_type会CE,要改成null_mapped_type。
AC Code
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define MAX_N 50005
#define MAX_V 200005
#define INF 2147483647
using namespace std;
using namespace __gnu_pbds;
typedef tree<pair<int,int>,null_mapped_type,less<pair<int,int> >,rb_tree_tag,tree_order_statistics_node_update> Tree;
typedef Tree::iterator git;
struct Splay
{
Tree t;
map<int,int> mp;
void ins(int x)
{
t.insert(make_pair(x,mp[x]=mp[x]+1));
}
void del(int x)
{
t.erase(make_pair(x,mp[x])),mp[x]=mp[x]-1;
}
int pre(int x)
{
if(t.empty()) return -INF;
git it=t.lower_bound(make_pair(x,0));
if(it==t.begin()) return -INF;
return (--it)->first;
}
int suc(int x)
{
if(t.empty()) return INF;
git it=t.upper_bound(make_pair(x,INF));
if(it==t.end()) return INF;
return it->first;
}
int kth(int x)
{
return t.find_by_order(x-1)->first;
}
int rk(int x)
{
return t.order_of_key(make_pair(x,1))+1;
}
};
int n,m;
int a[MAX_N];
Splay t[MAX_V];
void ins(int p,int k,int l,int r,int x)
{
t[k].ins(x);
if(l==r) return;
int mid=(l+r)>>1;
if(p<=mid) ins(p,k*2+1,l,mid,x);
else ins(p,k*2+2,mid+1,r,x);
}
int getrk(int a,int b,int k,int l,int r,int x)
{
if(a<=l && r<=b) return t[k].rk(x)-1;
int mid=(l+r)>>1,ans=0;
if(a<=mid) ans+=getrk(a,b,k*2+1,l,mid,x);
if(b>mid) ans+=getrk(a,b,k*2+2,mid+1,r,x);
return ans;
}
int getx(int a,int b,int k)
{
int l=0,r=INF;
while(r-l>1)
{
int mid=(l+r)>>1;
if(getrk(a,b,0,1,n,mid)<=k-1) l=mid;
else r=mid;
}
return l;
}
void upd(int p,int k,int l,int r,int x)
{
t[k].del(a[p]),t[k].ins(x);
if(l==r) return;
int mid=(l+r)>>1;
if(p<=mid) upd(p,k*2+1,l,mid,x);
else upd(p,k*2+2,mid+1,r,x);
}
int getpre(int a,int b,int k,int l,int r,int x)
{
if(a<=l && r<=b) return t[k].pre(x);
int mid=(l+r)>>1,ans=-INF;
if(a<=mid) ans=max(ans,getpre(a,b,k*2+1,l,mid,x));
if(b>mid) ans=max(ans,getpre(a,b,k*2+2,mid+1,r,x));
return ans;
}
int getsuc(int a,int b,int k,int l,int r,int x)
{
if(a<=l && r<=b) return t[k].suc(x);
int mid=(l+r)>>1,ans=INF;
if(a<=mid) ans=min(ans,getsuc(a,b,k*2+1,l,mid,x));
if(b>mid) ans=min(ans,getsuc(a,b,k*2+2,mid+1,r,x));
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),ins(i,0,1,n,a[i]);
int opt,l,r,k,p;
while(m--)
{
scanf("%d",&opt);
if(opt==1)
{
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",getrk(l,r,0,1,n,k)+1);
}
if(opt==2)
{
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",getx(l,r,k));
}
if(opt==3)
{
scanf("%d%d",&p,&k);
upd(p,0,1,n,k),a[p]=k;
}
if(opt==4)
{
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",getpre(l,r,0,1,n,k));
}
if(opt==5)
{
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",getsuc(l,r,0,1,n,k));
}
}
}
BZOJ 3196 Tyvj 1730 二逼平衡树:线段树套splay的更多相关文章
- BZOJ - 3196 Tyvj 1730 二逼平衡树 (线段树套treap)
题目链接 区间线段树套treap,空间复杂度$O(nlogn)$,时间复杂度除了查询区间k大是$O(log^3n)$以外都是$O(log^2n)$的. (据说线段树套线段树.树状数组套线段树也能过?) ...
- [bzoj3196]Tyvj 1730 二逼平衡树——线段树套平衡树
题目 Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查 ...
- 【bzoj3196】Tyvj 1730 二逼平衡树 线段树套Treap
题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义 ...
- [bzoj3196][Tyvj 1730][二逼平衡树] (线段树套treap)
Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在 ...
- bzoj 3196 Tyvj 1730 二逼平衡树(线段树套名次树)
3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1807 Solved: 772[Submit][Stat ...
- bzoj 3196/ Tyvj 1730 二逼平衡树 (线段树套平衡树)
3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec Memory Limit: 128 MB[Submit][Status][Discuss] Description ...
- BZOJ 3196: Tyvj 1730 二逼平衡树( 树套树 )
这道题做法应该很多吧.... 我用了线段树套treap.... -------------------------------------------------------------------- ...
- bzoj 3196 && luogu 3380 JoyOI 1730 二逼平衡树 (线段树套Treap)
链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3196 题面; 3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Se ...
- BZOJ 3196 Tyvj 1730 二逼平衡树 树套树 线段树 treap
http://www.lydsy.com/JudgeOnline/problem.php?id=3196 http://hzwer.com/2734.html 线段树套treap,似乎splay也可以 ...
随机推荐
- elastic search安装与本地测试
elastic search安装与本地测试 elastic search是一个全文搜索引擎 教程: 综合:http://www.ruanyifeng.com/blog/2017/08/elastics ...
- 洛谷 P2331 [SCOI2005]最大子矩阵
洛谷 这一题,乍一眼看上去只想到了最暴力的暴力--大概\(n^4\)吧. 仔细看看数据范围,发现\(1 \leq m \leq 2\),这就好办了,分两类讨论. 我先打了\(m=1\)的情况,拿了30 ...
- DRF(3) - 序列化组件(GET/PUT/DELETE接口设计)、视图优化组件
一.序列化组件 基于上篇随笔的表结构,通过序列化组件的ModelSerializer设计如下三个接口: GET 127.0.0.1:8000/books/{id} # 获取一条数据,返回值:{} PU ...
- 35个例子学会find
find的使用格式如下: $ find <指定目录> <指定条件> <指定动作> - <指定目录>: 所要搜索的目录及其所有子目录.默认为当前目录. - ...
- js, 树状菜单隐藏显示
js写的不是很严谨~~~嘿嘿 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"& ...
- SQL联接 外联接 内联接 完全联接 交叉联接
联接分为: 内联接 [inner join] 外联接 (左外联接,右外联接) [left join/left outer jo ...
- Hadoop中RPC协议小例子报错java.lang.reflect.UndeclaredThrowableException解决方法
最近在学习传智播客吴超老师的Hadoop视频,里面他在讲解RPC通信原理的过程中给了一个RPC的小例子,但是自己编写的过程中遇到一个小错误,整理如下: log4j:WARN No appenders ...
- 剑指offer编程题66道题 26-35
26.二叉搜索树与双向链表 题目描述 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表.要求不能创建任何新的结点,只能调整树中结点指针的指向. 中序遍历思路:按照右中左的顺序,中序遍历对 ...
- node第一个程序
var http = require('http') var url = require('url') var fs=require("fs") var router = requ ...
- 通过自动回复机器人学Mybatis:OGNL+log4j.properties
imooc视频学习笔记 ----> URL:http://www.imooc.com/learn/154 OGNL规则: 从哪里取?(作用域.取值范围,例如封装入一个对象,该对象就是取值范围) ...