4923: [Lydsy1706月赛]K小值查询 平衡树 非旋转Treap

国际惯例的题面:

这种维护排序序列,严格大于的进行操作的题都很套路......
我们按照[0,k],(k,2k],(2k,inf)分类讨论一下就好。
显然第一个区间的不会变化,第二个区间的会被平移进第一个区间,第三个区间的相对大小不会变化。
于是我们直接把第二个区间拆了重构,一个一个插入第一个区间即可。因为每次这样做最少减半,所以每个元素只会被重构log次,复杂度nlog^2n。
这种按照值域分离区间的操作,非旋转treap实现起来是最简单的......
然而第一次写非旋转treap还是出了一点问题,注意它的插入是通过按照值域分裂,新建点,再进行两次合并实现的。直接插入复杂度不对。
另外区间值域存在重合的情况两个treap不能直接合并......
我写的判定size的版本复杂度好像不对(不如暴力快?),于是只好预先生成fix值。

代码:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstdlib>
 4 const int maxn=1e5+1e2;
 5
 6 typedef std::pair<int,int> pii;
 7 __inline pii mp(const int &x,const int &y) { return std::make_pair(x,y); }
 8
 9 int seq[maxn],sql;
10 int stk[maxn],top;
11
12 struct Treap {
13     int lson[maxn],rson[maxn],lazy[maxn],val[maxn],siz[maxn],fix[maxn],cnt;
14
15     inline void init(int n) {
16         for(int i=1;i<=n;i++) fix[i] = i;
17         std::random_shuffle(fix+1,fix+1+n);
18     }
19     inline void apply(int pos,int x) {
20         if(pos) lazy[pos] += x , val[pos] -= x;
21     }
22     inline void push(int pos) {
23         if( lazy[pos] ) apply(lson[pos],lazy[pos]) , apply(rson[pos],lazy[pos]) , lazy[pos] = 0;
24     }
25     inline void maintain(int pos) {
26         siz[pos] = siz[lson[pos]] + siz[rson[pos]] + 1;
27     }
28
29     inline pii split(int pos,int dv) { // left is <= , right is > .
30         if( !pos ) return mp(0,0);
31         push(pos);
32         if(  dv < val[pos] ) {
33             pii spl = split(lson[pos],dv);
34             lson[pos] = spl.second , maintain(pos);
35             return mp(spl.first,pos);
36         } else {
37             pii spr = split(rson[pos],dv);
38             rson[pos] = spr.first , maintain(pos);
39             return mp(pos,spr.second);
40         }
41     }
42     inline int merge(int x,int y) {
43         if( !x || !y ) return x | y;
44         push(x) , push(y);
45         if( val[x] > val[y] ) std::swap(x,y);
46         if( fix[x] > fix[y] ) { // siz[x] is bigger .
47             lson[y] = merge(lson[y],x) , maintain(y);
48             return y;
49         } else {
50             rson[x] = merge(rson[x],y) , maintain(x);
51             return x;
52         }
53     }
54     inline void dfs(int pos) {
55         if( !pos ) return;
56         seq[++sql] = val[pos] , push(pos);
57         dfs(lson[pos]) , dfs(rson[pos]);
58         lson[pos] = rson[pos] = siz[pos] = 0 , stk[++top] = pos;
59     }
60     inline int kth(int pos,int k) { // return the kth value .
61         if( k == siz[lson[pos]] + 1 ) return val[pos];
62         return push(pos) , k <= siz[lson[pos]] ? kth(lson[pos],k) : kth(rson[pos],k-siz[lson[pos]]-1);
63     }
64     inline void insert(int &root,int x) {
65         val[++cnt] = x , siz[cnt] = 1;
66         pii sp = split(root,x);
67         root = merge(sp.first,cnt) , root = merge(root,sp.second);
68     }
69     inline void reinsert(int &root,int x) {
70         int cur = stk[top--];
71         val[cur] = x , siz[cur] = 1;
72         pii sp = split(root,x);
73         root = merge(sp.first,cur) , root = merge(root,sp.second);
74     }
75
76 }tp;
77
78 int main() {
79     static int n,m,root,rtl,rtm,rtr;
80     scanf("%d%d",&n,&m) , tp.init(n);
81     for(int i=1,t;i<=n;i++) scanf("%d",&t) , tp.insert(root,t);
82     for(int i=1,o,x;i<=m;i++) {
83         scanf("%d%d",&o,&x);
84         if( o == 1 ) printf("%d\n",tp.kth(root,x));
85         else if( o == 2 ) {
86             pii sp = tp.split(root,x);
87             rtl = sp.first , sp = tp.split(sp.second,x<<1);
88             rtm = sp.first , rtr = sp.second;
89             sql = 0 , tp.dfs(rtm) , tp.apply(rtr,x);
90             for(int i=1;i<=sql;i++) tp.reinsert(rtl,seq[i]-x);
91             root = tp.merge(rtl,rtr);
92         }
93     }
94     return 0;
95 }

Thupc被拒了好气啊!我们队可是有yzy大爷的!(即使这样都被拒了,一看就是我太菜了)

ありのままでいればいつも
只要坚守自我维持现状
あるべき私かここにいると
自己希望成为的样貌就存在于此
信じてまた 新しい夢を
不要放弃希望 崭新的梦想
精一杯描き出せばいい
再次奋力地去描绘就好
そう気づき始めたよ私
是啊 而我开始意识到
みんなとただ笑ってる未来を
大家单纯地绽放笑容的未来
夢見て
诚心盼望

原文地址:https://www.cnblogs.com/Cmd2001/p/8996861.html

时间: 2024-08-25 13:04:36

4923: [Lydsy1706月赛]K小值查询 平衡树 非旋转Treap的相关文章

普通平衡树——非旋转treap

题目: 此为平衡树系列第一道:普通平衡树您需要写一种数据结构,来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数,因输出最小的排名)4. 查询排名为x的数5. 求x的前驱(前驱定义为小于x,且最大的数)6. 求x的后继(后继定义为大于x,且最小的数) n<=100000 所有数字均在-107到107内. 输入样例: 10 1 106465 4 1 1 317721 1 460929 1 644985 1 841

[bzoj3065] 带插入区间第k小值 [重量平衡树套线段树]

题面 传送门 思路 发现强制在线了...... 本来可以树套树解决的问题,现在外层不能使用线段树了,拿什么替代呢? 我们需要一种支持单点插入.下套数据结构.数据结构上传合并复杂度最多单log,不能旋转的数据结构 这不是摆明了用重量平衡树吗? 我选了替罪羊树作为上层结构,下面套了一棵线段树,就做完了 查询的时候把替罪羊树上对应的log个区间提取出来,一起在底层权值线段树上二分即可 详见代码注释 Code #include<iostream> #include<cstdio> #inc

[BZOJ4923]K小值查询

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4923 好题啊!直接做肯定是不行的,我们需要发现一些性质.考虑减去k后对各个数的影响,对于(k,2k](即大于k小于等于2k)的数,它们被减后会小于等于k,但对于>2k的数,减去k后还是大于k的,且那些数的相对大小不变,因为要动态维护第k大,我们可以想到用平衡树,一般用splay,然后对于(k,2k]的数,直接暴力提取,一个个减去k,再暴力插入回去,大于2k的数直接打个标记就好了.我们分析

Bzoj3065 带插入区间K小值

Time Limit: 60 Sec  Memory Limit: 512 MBSubmit: 3436  Solved: 1103 Description 从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i].跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴.这时跳蚤国王决定理性愉悦一下,查询区间k小值.他每次向它的随从伏特提出这样的问题: 从左往右第x个到第y个跳蚤中,a[i]第k小的值是多少.这可难不倒伏特,他在脑袋里使用函数式线段树前缀和的方法水掉了跳蚤国王的询问.这时伏

BZOJ 3065 带插入区间K小值 替罪羊树套线段树

题目大意:带插入,单点修改的区间k小值在线查询. 思路:本年度做过最酸爽的题. 树套树的本质是一个外层不会动的树来套一个内层会动(或不会动)的树.两个树的时间复杂度相乘也就是差不多O(nlog^2n)左右.但是众所周知,高级数据结构经常会伴有庞大的常数,所以一般来说树套树的常数也不会小到哪去.所以在做这种题的时候先不要考虑常数的问题... 为什么要用替罪羊树呢?因为一般的平衡树都是会动的,这就很难办了.外层的树动了之后,内层的树肯定也是会动的.很显然,一般的二叉平衡树会经常会旋转,这样在动外层的

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

刚了一天的题终于切掉了,数据结构题的代码真**难调,这是我做过的第一道树套树题,做完后感觉对树套树都有阴影了......下面写一下做题记录. Portal Gun:[BZOJ3065]带插入区间k小值. 这道题的题面其实都提醒怎么做了,维护区间k小值用值域线段树,但要维护一个插入操作,树状数组套主席树也用不了,那么这道题还剩下平衡树可以搞,那就上平衡树吧. 我这里的做法,因为要维护序列的顺序,所以我这里用到替罪羊树套值域线段树:我们在替罪羊树的每个节点都套一颗值域线段树,记录以该节点为根的子树的

【bzoj3065】带插入区间K小值 替罪羊树套权值线段树

题目描述 从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i].跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴.这时跳蚤国王决定理性愉悦一下,查询区间k小值.他每次向它的随从伏特提出这样的问题: 从左往右第x个到第y个跳蚤中,a[i]第k小的值是多少.这可难不倒伏特,他在脑袋里使用函数式线段树前缀和的方法水掉了跳蚤国王的询问.这时伏特发现有些跳蚤跳久了弹跳力会有变化,有的会增大,有的会减少.这可难不倒伏特,他在脑袋里使用树状数组套线段树的方法水掉了跳蚤国王的询问.(orz 主席

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

3065: 带插入区间K小值 Time Limit: 60 Sec  Memory Limit: 512 MBSubmit: 1062  Solved: 253[Submit][Status] Description 从 前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i].跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴.这时跳蚤国王决定理性愉悦一 下,查询区间k小值.他每次向它的随从伏特提出这样的问题: 从左往右第x个到第y个跳蚤中,a[i]第k小的值是多少. 这可难不倒伏特,

【BZOJ】3065: 带插入区间K小值

题意:带插入.修改的区间k小值在线查询.(原序列n<=35000, 询问<=175000) #include <bits/stdc++.h> using namespace std; const int nTr=1000005, nSg=15000005, alphaA=4, alphaB=5; int STop; struct Seg *Snull; struct Seg { Seg *l, *r; int s, cnt; }Sg[nSg], *iSg=Sg, *bin[nSg]