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也可以 ...
随机推荐
- z waiting to receive.**B0100000023be50
[root@b ~]# rz▒z waiting to receive.**B0100000023be50
- Spring Mvc4 新特性(一)
前言 Spring Framework的Web层,由spring-web,spring-webmvc,spring-websocket和spring-webmvc-portlet模块组成. 很多人刚学 ...
- sql中in和exists的区别
in 和exists in是把外表和内表作hash 连接,而exists 是对外表作loop 循环,每次loop 循环再对内表进行查询. 一直以来认为exists 比in 效率高的说法是不准确的.如果 ...
- Sum---poj1844(数学题)
题目链接:http://poj.org/problem?id=1844 题意:给一个整数n,求当n由1到k的连续整数加或减组成时的最小的k. 如果n全部由加法组成,那么k可以组成k(k+1)/2,设减 ...
- SQL 2005 分页存储过程
-- ============================================= -- Description: <高效分页存储过程,适用于Sql2005以上> -- ...
- LAMP兄弟连 视频教程集
电驴的资源:http://www.verycd.com/topics/2843130/?ref=msg
- Win10 jdk的安装以及环境变量的配置,及需要注意的坑
此篇文章献给自己,希望下次长点记性 最近本人终于有时间开始学习appium,并且开始在电脑上配置环境,第一步就是在我那刚装的Win10 系统上安装jdk,过程并不顺利,由于之前都是用的win7,几乎都 ...
- Python高级教程-sorted
Python中的排序算法 排序是程序中经常用到的算法.通常规定,对于两个元素x和y,如果认为x<y,则返回-1,如果认为x == y,则返回0,如果认为x > y,则返回1,这样,排序算法 ...
- 访问hdfs里的文件
准备工作: 给hdfs里上传一份用于测试的文件 [root@master ~]# cat hello.txt hello 1 hello 2 hello 3 hello 4 [root@master ...
- vue指令详解
一.vue简绍 1. Vue.js是什么 Vue.js也称为Vue,读音/vju:/,类似view,错误读音v-u-e. 版本分为v1.0 和 v2.0 2.Vue.js的特点 1. 是一个构建 ...