bzoj 3196 树套树模板

然而我还是在继续刷水题。。。

终于解开了区间第k大的心结。。。

比较裸的线段树套平衡树,比较不好想的是求区间第k大时需要二分一下答案,然后问题就转化为了第一个操作。复杂度nlog3n。跑的比较慢。。。

在查前驱后继的时候写错了。。。如果要直接赋值ans的话前驱是k[x]<=z,后继是k[x]<z,如果都写<的话需要取max和min。。。(不是第一次犯这种错了)

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #define lc x*2,l,mid
  6 #define rc x*2+1,mid+1,r
  7 #define ls(x) ch[x][0]
  8 #define rs(x) ch[x][1]
  9 #define inf 0x3f3f3f3f
 10 using namespace std;
 11 int n,m;
 12 int root[50005*50];
 13 int size[50005*50],k[50005*50];
 14 int ch[50005*50][2],fa[50005*50];
 15 int a[50005];
 16 int cnt;
 17 inline void push_up(int x)
 18 {
 19     size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
 20     return ;
 21 }
 22 inline void rotate(int p)
 23 {
 24     int q=fa[p],y=fa[q],x=(ch[q][1]==p);
 25     ch[q][x]=ch[p][x^1];fa[ch[q][x]]=q;
 26     ch[p][x^1]=q;fa[q]=p;fa[p]=y;
 27     if(y)
 28     {
 29         if(ls(y)==q)ch[y][0]=p;
 30         else ch[y][1]=p;
 31     }
 32     push_up(q);push_up(p);
 33 }
 34 inline void splay(int now,int x)
 35 {
 36     for(int y;y=fa[x];rotate(x))
 37     {
 38         if(fa[y])
 39         {
 40             if((ls(y)==x&&ls(fa[y])==y)||(rs(y)==x&&rs(fa[y])==y))rotate(y);
 41             else rotate(x);
 42         }
 43     }
 44     root[now]=x;
 45 }
 46 inline void insert(int now,int x,int z)
 47 {
 48     size[x]++;
 49     while(ch[x][k[x]<z])x=ch[x][k[x]<z],size[x]++;
 50     ch[x][k[x]<z]=++cnt;fa[cnt]=x;size[cnt]=1;k[cnt]=z;splay(now,cnt);
 51 }
 52 inline void build(int x,int l,int r)
 53 {
 54     root[x]=++cnt;k[cnt]=a[l];size[cnt]=1;
 55     for(int i=l+1;i<=r;i++)insert(x,root[x],a[i]);
 56     int mid=(l+r)>>1;
 57     if(l<r)build(lc),build(rc);
 58     return ;
 59 }
 60 inline int fd(int x,int z)
 61 {
 62    int ans=0;
 63    while(x)
 64    {
 65          if(k[x]>z)
 66          {
 67               x=ch[x][0];
 68       }
 69       else ans+=size[ch[x][0]]+1,x=ch[x][1];
 70    }
 71    return ans;
 72 }
 73 inline int qur(int x,int l,int r,int ll,int rr,int kk)
 74 {
 75     if(ll<=l&&rr>=r)
 76     {
 77         return fd(root[x],kk);
 78     }
 79     int mid=(l+r)>>1;
 80     int ans=0;
 81     if(ll<=mid)ans+=qur(lc,ll,rr,kk);
 82     if(rr>mid)ans+=qur(rc,ll,rr,kk);
 83     return ans;
 84 }
 85 inline int find(int x,int z)
 86 {
 87     if(k[x]==z)return x;
 88     while(ch[x][k[x]<z])
 89     {
 90         x=ch[x][k[x]<z];if(k[x]==z)return x;
 91     }
 92     return 0;
 93 }
 94 inline void del(int now,int x)
 95 {
 96     splay(now,x);
 97     if(!ch[x][0])root[now]=ch[x][1],fa[ch[x][1]]=0;
 98     else if(!ch[x][1])root[now]=ch[x][0],fa[ch[x][0]]=0;
 99     else
100     {
101         fa[ch[x][0]]=0;int tmp=ch[x][0];
102         while(ch[tmp][1])tmp=ch[tmp][1];
103         splay(now,tmp);ch[tmp][1]=ch[x][1];fa[ch[x][1]]=tmp;push_up(tmp);
104     }
105 }
106 inline void gai(int x,int l,int r,int pos,int z)
107 {
108     insert(x,root[x],z);
109     int x1=find(root[x],a[pos]);
110     del(x,x1);
111     if(l==r)return ;
112     int mid=(l+r)>>1;
113     if(pos<=mid)gai(lc,pos,z);
114     else gai(rc,pos,z);
115 }
116 inline int pre(int x,int z)
117 {
118     int ans=-inf;
119     while(ch[x][k[x]<=z])
120     {
121         if(k[x]<=z)ans=k[x];
122         x=ch[x][k[x]<=z];
123     }if(k[x]<=z)ans=max(ans,k[x]);
124     return ans;
125 }
126 inline int suc(int x,int z)
127 {
128     int ans=inf;
129     while(ch[x][k[x]<z])
130     {
131         if(k[x]>=z)ans=k[x];
132         x=ch[x][k[x]<z];
133     }if(k[x]>=z)ans=min(ans,k[x]);
134     return ans;
135 }
136 inline int qur_pre(int x,int l,int r,int ll,int rr,int kk)
137 {
138     if(l>=ll&&r<=rr)
139     {
140         return pre(root[x],kk);
141     }
142     int ans=-inf;
143     int mid=(l+r)>>1;
144     if(ll<=mid)ans=max(ans,qur_pre(lc,ll,rr,kk));
145     if(rr>mid)ans=max(ans,qur_pre(rc,ll,rr,kk));
146     return ans;
147 }
148 inline int qur_suc(int x,int l,int r,int ll,int rr,int kk)
149 {
150     if(l>=ll&&r<=rr)
151     {
152         return suc(root[x],kk);
153     }
154     int ans=inf;
155     int mid=(l+r)>>1;
156     if(ll<=mid)ans=min(ans,qur_suc(lc,ll,rr,kk));
157     if(rr>mid)ans=min(ans,qur_suc(rc,ll,rr,kk));
158     return ans;
159 }
160 int mn,mx;
161 int main()
162 {
163     scanf("%d%d",&n,&m);mn=inf;mx=-inf;
164     for(int i=1;i<=n;i++)
165     {
166         scanf("%d",&a[i]);mn=min(mn,a[i]);mx=max(mx,a[i]);
167     }
168     build(1,1,n);
169     for(int i=1;i<=m;i++)
170     {
171         int t1;
172         scanf("%d",&t1);
173         int l,r,kk;
174         if(t1==1)
175         {
176            scanf("%d%d%d",&l,&r,&kk);
177            printf("%d\n",qur(1,1,n,l,r,kk-1)+1);
178         }
179         else if(t1==2)
180         {
181             scanf("%d%d%d",&l,&r,&kk);
182             int ha=mn;int ta=mx;
183             while(ha<=ta)
184             {
185                 int mid=(ha+ta)>>1;
186                 if(qur(1,1,n,l,r,mid)<kk)ha=mid+1;
187                 else ta=mid-1;
188             }
189             printf("%d\n",ha);
190         }
191         else if(t1==3)
192         {
193             scanf("%d%d",&l,&kk);
194             gai(1,1,n,l,kk);a[l]=kk;
195         }
196         else if(t1==4)
197         {
198             scanf("%d%d%d",&l,&r,&kk);
199             printf("%d\n",qur_pre(1,1,n,l,r,kk-1));
200         }
201         else
202         {
203             scanf("%d%d%d",&l,&r,&kk);
204             printf("%d\n",qur_suc(1,1,n,l,r,kk+1));
205         }
206     }
207     return 0;
208 }
时间: 2024-12-21 14:50:31

bzoj 3196 树套树模板的相关文章

BZOJ 3196 二逼平衡树 树套树

题目大意:...BZOJ挂了自己看去 好吧既然BZOJ挂了我还是贴上来吧0.0 破服务器 维护一种数据结构,提供下列操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱定义为小于x,且最大的数) 5.查询k在区间内的后继(后继定义为大于x,且最小的数) 其实一开始觉得这题是划分树主席树之类的 然后去了解了一下发现完全写不了... 后来才知道原来是树套树 以前想过线段树套树状数组 这数据范围别说树套树了连树状数组都开不开 正解应该是

BZOJ 3196 二逼平衡树 树套树(线段树套Treap)

题目大意: 写一种数据结构,他可以: 1.查询k在区间内的排名. 2.查询区间内排名为k的值 3.修改某一个值. 4.求k在区间内的前驱. 5.求k在区间内的后继. 思路:本来以为有什么只有神犇才知道的神一般的数据结构来维护它,问了别人之后,发现只是树套树.据说怎么套都行.我见识鄙陋,就只能线段树套Treap了. 这也是第一次写树套树,还1A了,有点开心. 写树套树,一定要确定自己对这两个树及其熟练,加上少量精细的思考,就可以完成树套树.(我只是弱渣,求神犇别D) 具体实现:第一层是线段树,第二

bzoj 1901: Zju2112 Dynamic Rankings(树套树)

1901: Zju2112 Dynamic Rankings 经典的带修改求区间第k小值问题 树套树模板,我是用的线段树套splay实现的,而且用的数组模拟的,所以可能空间略大,bzoj过了,zoj过不了. 思路很简单,用线段树维护区间,用splay维护区间内的权值,然后询问的时候,二分答案key,然后在区间内找小于key的数有多少个. 贴上模板: #include<stdio.h> #include<string.h> #include<algorithm> #def

树套树专题——bzoj 3110: [Zjoi2013] K大数查询 &amp; 3236 [Ahoi2013] 作业 题解

[原题1] 3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 978  Solved: 476 Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c 如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M 接下来M行,每行形如1 a b c或2 a b c Outpu

[BZOJ 3489] A simple rmq problem 【可持久化树套树】

题目链接:BZOJ - 3489 题目分析 “因为是OJ上的题,就简单点好了.”——出题人 真的..好..简单... 首先,我们求出每个数的前一个与它相同的数的位置,即 prev[i] ,如果前面没有相同的数,prev[i] = 0. 再求出每个数的后一个与它相同的数的位置,即 next[i], 如果后面没有相同的数,next[i] = n + 1. 这样,对于 l > prev[i], r < next[i] 的区间,i 这个数在区间中至多出现一次. 那么我们要求的就是:符合 prev[i]

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

洛谷 P3380 [模板]二逼平衡树(树套树) 线段树套treap: 就是线段树每个节点放一个treap.建树复杂度应该是$n log n$,操作1,3,4,5的复杂度是$(log n)^2$,操作2的复杂度是$(log n)^3$. 操作3:找到线段树的对应叶子节点后找到要删除的值,在回溯的时候更新线段树相关的每一个节点(在treap中去掉要删除的值,再加入要加入的值) 操作1:将操作转化为统计(这个区间[l,r]内小于x的数的个数)+1.那么通过线段树将区间分解,然后对分解出的每一个区间对应

「模板」 树套树

「模板」 树套树 <题目链接> 线段树套 SBT. 有生以来写过的最长代码. 虽然能过,但我删除 SBT 点的时候没回收内存!写了就 RE! 先放上来吧,回收内存调出来了再修改qwq. #include <algorithm> #include <climits> #include <cstdio> using std::max; using std::min; const int MAXN=50010; int n,m; class SegmentTree

「luogu3380」【模板】二逼平衡树(树套树)

「luogu3380」[模板]二逼平衡树(树套树) 传送门 我写的树套树--线段树套平衡树. 线段树上的每一个节点都是一棵 \(\text{FHQ Treap}\) ,然后我们就可以根据平衡树的基本操作以及线段树上区间信息可合并的性质来实现了,具体细节看代码都懂. 参考代码: #include <algorithm> #include <cstdlib> #include <cstdio> #define rg register #define file(x) freo

BZOJ 3110: [Zjoi2013]K大数查询 [树套树]

3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6050  Solved: 2007[Submit][Status][Discuss] Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M接下来M行,每行形如1 a

bzoj 3295: [Cqoi2011]动态逆序对(树套树 or CDQ分治)

Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数.以下n行每行包含一个1到n之间的正整数,即初始排列.以下m行每行一个正整数,依次为每次删除的元素. Output 输出包含m行,依次为删除每个元素之前,逆序对的个数. Sample Input 5 4 1 5 3