Bzoj3196 Tyvj 1730 二逼平衡树

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 3350  Solved: 1324

Description

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

Input

第一行两个数 n,m 表示长度为n的有序序列和m个操作
第二行有n个数,表示有序序列
下面有m行,opt表示操作标号
若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间[l,r]的排名
若opt=2 则为操作2,之后有三个数l,r,k 表示查询区间[l,r]内排名为k的数
若opt=3 则为操作3,之后有两个数pos,k 表示将pos位置的数修改为k
若opt=4 则为操作4,之后有三个数l,r,k 表示查询区间[l,r]内k的前驱
若opt=5 则为操作5,之后有三个数l,r,k 表示查询区间[l,r]内k的后继

Output

对于操作1,2,4,5各输出一行,表示查询结果

Sample Input

9 6
4 2 2 1 9 4 0 1 1
2 1 4 3
3 4 10
2 1 4 3
1 2 5 9
4 3 9 5
5 2 8 5

Sample Output

2
4
3
4
9

HINT

1.n和m的数据范围:n,m<=50000

2.序列中每个数的数据范围:[0,1e8]

3.虽然原题没有,但事实上5操作的k可能为负数

Source

树套树

线段树套平衡树(treap)

外层线段树维护区间,内层treap维护该区间内的数值

代码超长看着就累

Bzoj过了,Tyvj上最后两个点过不去,迷

标题仿佛在嘲笑那些光写平衡树的人,又仿佛在嘲讽我这种模板题调一下午的人……

小发现:对拍的时候,要是每次错得不一样,基本上可以确定是旋转错了/结点删错了

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<cstdlib>
  6 #include<ctime>
  7 using namespace std;
  8 const int mxn=50010;
  9 int read(){
 10     int x=0,f=1;char ch=getchar();
 11     while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
 12     while(ch>=‘0‘ && ch<=‘9‘){x=x*10-‘0‘+ch;ch=getchar();}
 13     return x*f;
 14 }
 15 int n,m,root[mxn<<2];
 16 struct node{
 17     int l,r;int w,rand;int cnt,size;
 18 }t[mxn*60];
 19 int cnt=0;
 20 void pushup(int rt){
 21     t[rt].size=t[t[rt].l].size+t[t[rt].r].size+t[rt].cnt;return;
 22 }
 23 void lturn(int &rt){
 24     int tmp=t[rt].r;
 25     t[rt].r=t[tmp].l; t[tmp].l=rt;
 26     t[tmp].size=t[rt].size;
 27     pushup(rt);    rt=tmp;
 28     return;
 29 }
 30 void rturn(int &rt){
 31     int tmp=t[rt].l;
 32     t[rt].l=t[tmp].r; t[tmp].r=rt;
 33     t[tmp].size=t[rt].size;
 34     pushup(rt);    rt=tmp;
 35     return;
 36 }
 37 void insert(int w,int &rt){
 38     if(!rt){
 39         rt=++cnt;
 40         t[rt].l=t[rt].r=0;
 41         t[rt].size=t[rt].cnt=1;
 42         t[rt].rand=rand();
 43         t[rt].w=w;
 44         return;
 45     }
 46     t[rt].size++;
 47     if(t[rt].w==w){t[rt].cnt++;return;}
 48     if(w<t[rt].w){insert(w,t[rt].l);if(t[t[rt].l].rand>t[rt].rand)rturn(rt);}
 49     else {insert(w,t[rt].r);if(t[t[rt].r].rand>t[rt].rand)lturn(rt);}
 50     return;
 51 }
 52 void Del(int w,int &rt){
 53     if(t[rt].w==w){
 54         if(t[rt].cnt>1){t[rt].cnt--;t[rt].size--;return;}
 55         if(t[rt].l*t[rt].r==0)rt=t[rt].l+t[rt].r;
 56         else
 57             if(t[t[rt].l].rand>t[t[rt].r].rand)
 58             {rturn(rt);Del(w,rt);}
 59             else{lturn(rt);Del(w,rt);}//开始写成Del(w,t[rt].l) WA了
 60         return;
 61     }
 62     else if(w>t[rt].w)Del(w,t[rt].r);
 63         else Del(w,t[rt].l);
 64     t[rt].size--;
 65     return;
 66 }
 67 //
 68 void Build(int p,int v,int l,int r,int rt){
 69     insert(v,root[rt]);
 70     if(l==r)return;
 71     int mid=(l+r)>>1;
 72     if(p<=mid)Build(p,v,l,mid,rt<<1);
 73     else Build(p,v,mid+1,r,rt<<1|1);
 74     return;
 75 }
 76 void update(int p,int last,int v,int l,int r,int rt){//改变某位置的值
 77 //    printf("p:%d last:%d v:%d l:%d r:%d rt:%d\n",p,last,v,l,r,rt);
 78     Del(last,root[rt]);//删除旧值
 79     insert(v,root[rt]);//添加新值
 80     if(l==r)return;
 81     int mid=(l+r)>>1;
 82     if(p<=mid)update(p,last,v,l,mid,rt<<1);
 83     else update(p,last,v,mid+1,r,rt<<1|1);
 84     return;
 85 }
 86 //
 87 int rank1(int w,int rt){
 88     if(!rt)return 0;
 89     if(w==t[rt].w){return t[t[rt].l].size;}
 90     if(w<t[rt].w)return rank1(w,t[rt].l);
 91     else return t[t[rt].l].size+t[rt].cnt+rank1(w,t[rt].r);
 92 }
 93 int Qrk(int L,int R,int num,int l,int r,int rt){//查找num的排名
 94     if(L<=l && r<=R)return rank1(num,root[rt]);
 95     int mid=(l+r)>>1;
 96     int res=0;
 97     if(L<=mid)res+=Qrk(L,R,num,l,mid,rt<<1);
 98     if(R>mid)res+=Qrk(L,R,num,mid+1,r,rt<<1|1);
 99     return res;
100 }
101 int Qnum(int L,int R,int k){//查找排名为k的数
102     int l=0,r=1e9,ans=0;
103     while(l<=r){//二分答案
104         int mid=(l+r)>>1;
105         int res=Qrk(L,R,mid,1,n,1)+1;
106         if(res<=k){l=mid+1;ans=mid;}
107         else r=mid-1;
108     }
109     return ans;
110 }
111 int res=0;//存储前驱/后继答案
112 void Pre(int w,int rt){
113     if(!rt)return;
114     if(t[rt].w<w){res=max(res,t[rt].w);Pre(w,t[rt].r);}
115     else Pre(w,t[rt].l);
116     return;
117 }
118 void Sub(int w,int rt){
119     if(!rt)return;
120     if(t[rt].w>w){res=min(res,t[rt].w);Sub(w,t[rt].l);}
121     else Sub(w,t[rt].r);
122     return;
123 }
124 void Qpre(int L,int R,int num,int l,int r,int rt){
125     if(L<=l && r<=R){Pre(num,root[rt]);return;}
126     int mid=(l+r)>>1;
127     if(L<=mid)Qpre(L,R,num,l,mid,rt<<1);
128     if(R>mid)Qpre(L,R,num,mid+1,r,rt<<1|1);
129     return;
130 }
131 void Qsub(int L,int R,int num,int l,int r,int rt){
132 //    printf("!\n");
133     if(L<=l && r<=R){Sub(num,root[rt]);return;}
134     int mid=(l+r)>>1;
135     if(L<=mid)Qsub(L,R,num,l,mid,rt<<1);
136     if(R>mid)Qsub(L,R,num,mid+1,r,rt<<1|1);
137     return;
138 }
139 int a[mxn];
140 int main(){
141     int i,j,x,y,w;
142     n=read();m=read();
143     srand(time(0));
144     for(i=1;i<=n;i++){a[i]=read();Build(i,a[i],1,n,1);}
145     int op;
146     while(m--){
147         op=read();
148         switch(op){
149             case 1:{
150                 x=read();y=read();w=read();
151                 printf("%d\n",Qrk(x,y,w,1,n,1)+1);
152                 break;
153             }
154             case 2:{
155                 x=read();y=read();w=read();
156                 printf("%d\n",Qnum(x,y,w));
157                 break;
158             }
159             case 3:{
160                 x=read();y=read();
161                 update(x,a[x],y,1,n,1);
162                 a[x]=y;
163                 break;
164             }
165             case 4:{
166                 x=read();y=read();w=read();
167                 res=-1e9;
168                 Qpre(x,y,w,1,n,1);
169                 printf("%d\n",res);
170                 break;
171             }
172             case 5:{
173                 x=read();y=read();w=read();
174                 res=1e9;
175                 Qsub(x,y,w,1,n,1);
176                 printf("%d\n",res);
177                 break;
178             }
179         }
180     }
181     return 0;
182 }
时间: 2024-10-03 13:27:20

Bzoj3196 Tyvj 1730 二逼平衡树的相关文章

【线段树套平衡树】【pb_ds】bzoj3196 Tyvj 1730 二逼平衡树

线段树套pb_ds里的平衡树,在洛谷OJ上测试,后三个测试点TLE #include<cstdio> #include<algorithm> #include<ext/pb_ds/assoc_container.hpp> #include<ext/pb_ds/tree_policy.hpp> #define N 50010 #define INF 2147483647 using namespace std; using namespace __gnu_pb

[bzoj3196][Tyvj 1730][二逼平衡树] (线段树套treap)

Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱定义为小于x,且最大的数) 5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,m 表示长度为n的有序序列和m个操作 第二行有n个数,表示有序序列 下面有m行,opt表示操作标号 若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间

【分块】bzoj3196 Tyvj 1730 二逼平衡树

分块 或 树套树. 在每个块中维护一个有序表,查询时各种二分,全都是分块的经典操作,就不详细说了. 块的大小定为sqrt(n*log2(n))比较快. 1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 int sum,sz,l[400],r[400],num[51001],a[51001],b[5100

【函数式权值分块】【分块】bzoj3196 Tyvj 1730 二逼平衡树

#include<cstdio> #include<cmath> #include<algorithm> using namespace std; #define N 50001 #define SQRT 227 int n,m,xs[N],ys[N],ks[N],op[N],en,ma[100001],en2,a[100001]; int num[N],l[SQRT],r[SQRT],sumv[SQRT],sum=1;//分块 int num2[100001],l2[

【带修莫队】【权值分块】bzoj3196 Tyvj 1730 二逼平衡树

这题用了三种算法写: 分块+二分:O(n*sqrt(n*log(n)) 函数式权值分块:O(n*sqrt(n)) 带修莫队+权值分块:O(n5/3) 结果……复杂度越高的实际上跑得越快……最后这个竟然进第一页了…… #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int f,C; inline void R(int &

bzoj 3196/ Tyvj 1730 二逼平衡树 (线段树套平衡树)

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,

【BZOJ 3196】Tyvj 1730 二逼平衡树

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 842  Solved: 350 [Submit][Status] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱定义为小于x,且最大的数) 5.查询k在区间内的后继(后继定义为大于x,

BZOJ 3196: Tyvj 1730 二逼平衡树( 树套树 )

这道题做法应该很多吧.... 我用了线段树套treap.... -------------------------------------------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<cstdlib> #include<ios

[Tyvj 1730] 二逼平衡树

先来一发题面QwQ [TYVJ1730]二逼平衡树 Time Limit:2 s   Memory Limit:512 MB Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,m 表示长度为n的有序序列和m个操作第二行有n个数