洛谷p3380模板二逼平衡树(树套树)

     2022-10-14     569

关键词:

洛谷 P3380 【模板】二逼平衡树(树套树)

线段树套treap:

就是线段树每个节点放一个treap。建树复杂度应该是$n log n$,操作1,3,4,5的复杂度是$(log n)^2$,操作2的复杂度是$(log n)^3$。

操作3:找到线段树的对应叶子节点后找到要删除的值,在回溯的时候更新线段树相关的每一个节点(在treap中去掉要删除的值,再加入要加入的值)

操作1:将操作转化为统计(这个区间[l,r]内小于x的数的个数)+1。那么通过线段树将区间分解,然后对分解出的每一个区间对应的treap求小于x的数的个数,最后将这些答案加起来再加一得到最终答案。

操作4:通过线段树将区间分解,然后对分解出的每一个区间对应的treap求x的前驱,取这些前驱的最值。

操作5:通过线段树将区间分解,然后对分解出的每一个区间对应的treap求x的后继,取这些后继的最值。

操作2:咋一看似乎没什么好方法。看题解,可以将操作转化为找出这个区间[l,r]内最小的x,使得区间内小于x的数不少于k-1个(即x的排名不低于k)二分答案即可。

  1 #include<cstdio>
  2 #include<algorithm>
  3 using namespace std;
  4 #define MAXI 2147483647
  5 #define lc (num<<1)
  6 #define rc (num<<1|1)
  7 #define mid ((l+r)>>1)
  8 int rand1()
  9 {
 10     static int x=471;
 11     return x=(48271LL*x+1)%2147483647;
 12 }
 13 struct Node
 14 {
 15     Node* ch[2];
 16     int r;//优先级
 17     int v;//value
 18     int size;//维护子树的节点个数
 19     int num;//当前数字出现次数
 20     int cmp(int x) const//要在当前节点的哪个子树去查找,0左1右
 21     {
 22         if(x==v)    return -1;
 23         return v<x;
 24     }
 25     void upd()
 26     {
 27         size=num;
 28         if(ch[0]!=NULL)    size+=ch[0]->size;
 29         if(ch[1]!=NULL)    size+=ch[1]->size;
 30     }
 31 }nodes[3001000];
 32 int mem;
 33 void rotate(Node* &o,int d)
 34 {
 35     Node* t=o->ch[d^1];o->ch[d^1]=t->ch[d];t->ch[d]=o;
 36     o->upd();t->upd();
 37     o=t;
 38 }
 39 Node* getnode(){ return &nodes[mem++];}
 40 void insert(Node* &o,int x)
 41 {
 42     if(o==NULL)
 43     {
 44         o=getnode();o->ch[0]=o->ch[1]=NULL;
 45         o->v=x;o->r=rand1();o->num=1;
 46     }
 47     else
 48     {
 49         if(o->v==x)    ++(o->num);
 50         else
 51         {
 52             int d=o->v < x;
 53             insert(o->ch[d],x);
 54             if(o->r < o->ch[d]->r)    rotate(o,d^1);
 55         }
 56     }
 57     o->upd();
 58 }
 59 void remove(Node* &o,int x)
 60 {
 61     int d=o->cmp(x);
 62     if(d==-1)
 63     {
 64         if(o->num > 0)
 65         {
 66             --(o->num);
 67         }
 68         if(o->num == 0)
 69         {
 70             if(o->ch[0]==NULL)    o=o->ch[1];
 71             else if(o->ch[1]==NULL)    o=o->ch[0];
 72             else
 73             {
 74                 int d2=o->ch[1]->r < o->ch[0]->r;
 75                 rotate(o,d2);
 76                 remove(o->ch[d2],x);
 77             }
 78         }
 79     }
 80     else    remove(o->ch[d],x);
 81     if(o!=NULL)    o->upd();
 82 }
 83 bool find(Node* o,int x)
 84 {
 85     int d;
 86     while(o!=NULL)
 87     {
 88         d=o->cmp(x);
 89         if(d==-1)    return 1;
 90         else o=o->ch[d];
 91     }
 92     return 0;
 93 }
 94 int kth(Node* o,int k)
 95 {
 96     if(o==NULL||k<=0||k > o->size)    return 0;
 97     int s= o->ch[0]==NULL ? 0 : o->ch[0]->size;
 98     if(k>s&&k<=s+ o->num)    return o->v;
 99     else if(k<=s)    return kth(o->ch[0],k);
100     else    return kth(o->ch[1],k-s- o->num);
101 }
102 int rk(Node* o,int x)
103 {
104     if(o==NULL)    return 0;
105     int r=o->ch[0]==NULL ? 0 : o->ch[0]->size;
106     if(x==o->v)    return r;
107     else    if(x<o->v)    return rk(o->ch[0],x);
108     else    return r+ o->num +rk(o->ch[1],x);
109 }
110 int pre(Node* o,int x)
111 {
112     if(o==NULL)    return -MAXI;
113     int d=o->cmp(x);
114     if(d<=0)    return pre(o->ch[0],x);
115     else    return max(o->v,pre(o->ch[1],x));
116 }
117 int nxt(Node* o,int x)
118 {
119     if(o==NULL)    return MAXI;
120     int d=o->cmp(x);
121     if(d!=0)    return nxt(o->ch[1],x);
122     else    return min(o->v,nxt(o->ch[0],x));
123 }
124 Node* root[200100];
125 int x,L,R,k,d,n,m;//所有操作的操作区间用[L,R]表示而不是[l,r]
126 int a[50010];
127 
128 
129 int rk1(int l,int r,int num)//返回区间内小于x的数的个数
130 {
131     if(L<=l&&r<=R)
132     {
133         return rk(root[num],x);
134     }
135     int ans=0;
136     if(L<=mid)    ans+=rk1(l,mid,lc);
137     if(mid<R)    ans+=rk1(mid+1,r,rc);
138     return ans;
139 }
140 int pre1(int l,int r,int num)
141 {
142     if(L<=l&&r<=R)
143     {
144         return pre(root[num],x);
145     }
146     int ans=-2147483647;
147     if(L<=mid)    ans=max(ans,pre1(l,mid,lc));
148     if(mid<R)    ans=max(ans,pre1(mid+1,r,rc));
149     return ans;
150 }
151 int nxt1(int l,int r,int num)
152 {
153     if(L<=l&&r<=R)
154     {
155         return nxt(root[num],x);
156     }
157     int ans=2147483647;
158     if(L<=mid)    ans=min(ans,nxt1(l,mid,lc));
159     if(mid<R)    ans=min(ans,nxt1(mid+1,r,rc));
160     return ans;
161 }
162 void change(int l,int r,int num)
163 {
164     if(l<r)
165     {
166         if(k<=mid)    change(l,mid,lc);
167         else    change(mid+1,r,rc);
168     }
169     else
170     {
171         d=kth(root[num],1);
172     }
173     remove(root[num],d);
174     insert(root[num],x);
175 }
176 void build(int l,int r,int num)
177 {
178     for(int i=l;i<=r;i++)    insert(root[num],a[i]);
179     if(l<r)
180     {
181         build(l,mid,lc);
182         build(mid+1,r,rc);
183     }
184 }
185 int main()
186 {
187     int i,idx,l,r;
188     scanf("%d%d",&n,&m);
189     for(i=1;i<=n;i++)    scanf("%d",&a[i]);
190     build(1,n,1);
191     for(i=1;i<=m;i++)
192     {
193         scanf("%d",&idx);
194         if(idx==1)
195         {
196             scanf("%d%d%d",&L,&R,&x);
197             printf("%d
",rk1(1,n,1)+1);
198         }
199         else if(idx==2)
200         {
201             scanf("%d%d%d",&L,&R,&k);
202             l=-1;r=100000000;
203             while(l<r-1)
204             {
205                 x=(l+r)/2;
206                 if(rk1(1,n,1)+1<=k)    l=x;
207                 else    r=x;
208             }
209             x=r;printf("%d
",pre1(1,n,1));;
210         }
211         else if(idx==3)
212         {
213             scanf("%d%d",&k,&x);
214             change(1,n,1);
215         }
216         else if(idx==4)
217         {
218             scanf("%d%d%d",&L,&R,&x);
219             printf("%d
",pre1(1,n,1));
220         }
221         else if(idx==5)
222         {
223             scanf("%d%d%d",&L,&R,&x);
224             printf("%d
",nxt1(1,n,1));
225         }
226     }
227     return 0;
228 }

 

[模板]洛谷t3380二逼平衡树线段树套splay

时隔一个月后,终于攻克了二分求K大的难题。。。特此纪念10.3好好的树套树模板题怎么没有一份线段树套平衡树的“标准”题解呢。。。虽然这方法比较low,但我还是来贴一发。。。据说这题常数巨大,若干份线段树套BST的代... 查看详情

洛谷3380二逼平衡树(树套树)

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

luogu3380模板二逼平衡树(树套树)

#include<iostream>#include<cstdlib>#include<cstdio>#include<ctime>usingnamespacestd;intn,m,cnt,a[50005],rot[200005],opt,ans,uu,vv,ww;structNode{intl,r,siz,hav,val,rnd;}nd[40000 查看详情

「luogu3380」模板二逼平衡树(树套树)(代码片段)

「luogu3380」【模板】二逼平衡树(树套树)传送门我写的树套树——线段树套平衡树。线段树上的每一个节点都是一棵( extFHQTreap),然后我们就可以根据平衡树的基本操作以及线段树上区间信息可合并的性质来实现了,具体细节... 查看详情

bzoj3196二逼平衡树树套树

3196:Tyvj1730二逼平衡树TimeLimit: 10Sec  MemoryLimit: 128MBSubmit: 3776  Solved: 1483Description您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查... 查看详情

bzoj3196:tyvj1730二逼平衡树树套树

地址:http://www.lydsy.com/JudgeOnline/problem.php?id=3196题目:3196:Tyvj1730二逼平衡树TimeLimit: 10Sec  MemoryLimit: 128MBSubmit: 4320  Solved: 1662[Submit][Status][Discu 查看详情

模板二逼平衡树(树套树)(代码片段)

题面题解过年的假期里肯定要用硬核数据结构打发时间啊所以我大胆尝试,用了一种速度不能算最快但是码量绝对是很大的一种方法居然控制在了6KB以内线段树套红黑树(逃这是一次前所未有的尝试因为线段树套平衡树求区间第... 查看详情

bzoj3196[tyvj1730]二逼平衡树树套树线段树套scapegoat_tree

人傻自带大常数#include<cstdio>#include<cstring>#include<iostream>#defineMAXN1500005usingnamespacestd;constdoubleA=0.756;constintinf=100000000;intn,m,a[50005];structScapeGoat_Tree{ScapeGoat_ 查看详情

[tyvj1730]二逼平衡树线段树套平衡树

来一发树套树。1A也是很感动QAQ就是时间复杂度略大。而且好像还有其他打法。谨以此纪念此类型树套树入门#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>usingnamespacestd;#definepos(i,a,b)for(inti=(a);i<=(b) 查看详情

二逼平衡树(树套树)(代码片段)

第一次写树套树,在一定帮助下学习,调码3h。用线段树套平衡树,对于区间内排名的查询可以解决了;//$O(log^2n)$对于查询区间排名为k的数,二分答案再判断;//$O(log^3n)$修改数值直接修改;//$O(log^2n)$前驱后继,线段树递归区间... 查看详情

bzoj3196:tyvj1730二逼平衡树

...,我记得这个sb题,,搞了一整天,(吐槽,本来开心去洛谷提交,结果不一样,mdzz)树套树,,,各种套。。。都是在区间内最基本的查询1#include<bits/stdc++.h>2#defineN1000053#defineLLlonglong4#defineinf0x3f3f3f3f5usingnamespacestd;6inlineintr... 查看详情

bzoj3196:tyvj1730二逼平衡树

这题太经典了……树套树模板题……写着超级爽,思路流畅,最后卡了一会儿常就过去了……我就是来粘个代码的……fhqtreap写着比较舒服1/**************************************************************2Problem:31963User:10909007154Language:Pascal5Result:A... 查看详情

二逼平衡树(树套树)(代码片段)

传送门这道题的做法……我学的是最经典的线段树套平衡树。因为发现其实这题的题目描述和普通平衡树非常的相似……只是这次是在给定的区间中。所以我们能想象到用线段树维护区间,然后每个线段树的节点都是一颗平衡树... 查看详情

[bzoj3196]二逼平衡树

人生第一次写树套树 这题是区间上的数值操作,所以我们用区间数据结构套数值数据结构我选择了线段树套splay其实就是对于线段树的每个节点$x$,若它代表的区间为$[l,r]$,则在这个线段树节点上建一棵含$A_{lcdotsr}$的splay对... 查看详情

bzoj3196:tyvj1730二逼平衡树

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

模板二逼平衡树(代码片段)

线段树套splay:  这是个永远不想打第二遍的模板1#include<bits/stdc++.h>2#defineRregister3usingnamespacestd;4constintN=50010,NN=2000010,oo=2147483647;5intn,m,a[N];6intfa[NN],ch[NN][2],v[NN],siz[NN],cnt[NN],tot;7intls 查看详情

权值线段树套序列线段树(代码片段)

【模板】权值线段树套序列线段树P3380【模板】二逼平衡树(树套树)主要思路如下:外层为权值线段树,内层为动态开点线段树,也就是每个权值线段树上的节点开一个动态开点线段树。外层的权值线段树支持查询排名,内层... 查看详情

洛谷3380模板二逼平衡树(树状数组套权值线段树)

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