码迷,mamicode.com
首页 > 其他好文 > 详细

【BZOJ3196】Tyvj 1730 二逼平衡树

时间:2016-01-23 01:03:09      阅读:180      评论:0      收藏:0      [点我收藏+]

标签:

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可能为负数
 
题解
树套树,调了好久,至今都不是很清楚为什么删除节点的时候不能直接减一而必须先....说不清楚了,在代码里体现吧
  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<iostream>
  4 using namespace std;
  5 const int inf=100000000,N=3000001,M=200001;
  6 int num[N],rnd[N],size[N],ls[N],rs[N],root[M],w[N],a[M];
  7 int sz,n,m,opt,l,r;
  8 void updata(int k){size[k]=size[ls[k]]+size[rs[k]]+w[k];}
  9 void rturn(int &k){int t=ls[k];ls[k]=rs[t];rs[t]=k;size[t]=size[k];updata(k);k=t;}
 10 void lturn(int &k){int t=rs[k];rs[k]=ls[t];ls[t]=k;size[t]=size[k];updata(k);k=t;}
 11 void insert(int &k,int x){
 12     if (!k){
 13         k=++sz;num[k]=x;rnd[k]=rand();size[k]=w[k]=1;return;
 14     }
 15     size[k]++;
 16     if (x==num[k]) {w[k]++;return;}
 17     if (x<num[k]) {insert(ls[k],x);if (rnd[ls[k]]<rnd[k]) rturn(k);}
 18     if (x>num[k]) {insert(rs[k],x);if (rnd[rs[k]]<rnd[k]) lturn(k);}
 19 }
 20  
 21 void del(int &k,int x){
 22     if (!k) return;
 23     if (num[k]==x){
 24         if (w[k]>1){w[k]--;size[k]--;return;}//就是这里,不知道为什么不是在前面直接size[k]--
 25         if(ls[k]*rs[k]==0){k=ls[k]+rs[k]; return;}
 26         if (rnd[ls[k]]<rnd[rs[k]])rturn(k),del(k,x);
 27         else lturn(k),del(k,x);
 28     }
 29     else if (num[k]>x) del(ls[k],x),size[k]--;else del(rs[k],x),size[k]--;
 30 }
 31  
 32 void change(int pos,int x){
 33     int k=1,l=1,r=n,mid=(l+r)>>1;
 34     while (l!=r){
 35         mid=(l+r)>>1;
 36         del(root[k],a[pos]);
 37         insert(root[k],x);
 38         if (mid>=pos)k=k<<1,r=mid;
 39         else k=k<<1|1,l=mid+1;
 40     }
 41     mid=(l+r)>>1;
 42     del(root[k],a[pos]);
 43     insert(root[k],x);    
 44 }
 45  
 46 int solve_rank(int k,int x){
 47     if (!k) return 0;
 48     int l=ls[k],r=rs[k];
 49     if (num[k]==x) return size[l];
 50     else if (num[k]>x) return solve_rank(l,x);
 51     else return solve_rank(r,x)+size[l]+w[k];
 52 }
 53  
 54 int get_rank(int k,int l,int r,int L,int R,int x){
 55     if (l==L&&r==R) return (solve_rank(root[k],x));
 56     int mid=(l+r)>>1;
 57     if (R<=mid) return get_rank(k<<1,l,mid,L,R,x);
 58     else if (L>mid) return get_rank(k<<1|1,mid+1,r,L,R,x);
 59     else return get_rank(k<<1,l,mid,L,mid,x)+get_rank(k<<1|1,mid+1,r,mid+1,R,x);
 60 }
 61  
 62 void build(int x,int y){
 63     int l=1,r=n,k=1,mid=(l+r)>>1;
 64     while(l!=r){
 65         insert(root[k],y);
 66         if (mid>=x) r=mid,mid=(l+r)>>1,k=k<<1;
 67         else l=mid+1,mid=(l+r)>>1,k=k<<1|1;
 68     }
 69     insert(root[k],y);
 70 }
 71  
 72 int get_num(int x,int y,int z){
 73     int l=1,r=inf,ans;
 74     while (l<=r){
 75         int mid=(l+r)>>1;
 76         int tmp=get_rank(1,1,n,x,y,mid);
 77         if (tmp<=z) ans=mid,l=mid+1;//因为有重复的数字,tmp偏小 
 78         else r=mid-1;
 79     }
 80     return ans;
 81 }
 82  
 83 int solve_pre(int k,int x){
 84     int l=ls[k],r=rs[k];
 85     if (!k) return 0;
 86     if (num[k]<x) return max(num[k],solve_pre(r,x));//这里不要顺手打上=
 87     else return solve_pre(l,x);
 88 }
 89  
 90 int get_pre(int k,int l,int r,int L,int R,int x){
 91     if (l==L&&r==R) return (solve_pre(root[k],x));
 92     int mid=(l+r)>>1;
 93     if (R<=mid) return get_pre(k<<1,l,mid,L,R,x);
 94     else if (L>mid) return get_pre(k<<1|1,mid+1,r,L,R,x);
 95     else return max(get_pre(k<<1,l,mid,L,mid,x),get_pre(k<<1|1,mid+1,r,mid+1,R,x));
 96 }
 97  
 98 int solve_after(int k,int x){
 99     int l=ls[k],r=rs[k];
100     if (!k) return inf;
101     if (num[k]>x) return min(num[k],solve_after(l,x));//这里不要顺手打上=*2
102     else return solve_after(r,x);
103 }
104  
105 int get_after(int k,int l,int r,int L,int R,int x){
106     if (l==L&&r==R) return (solve_after(root[k],x));
107     int mid=(l+r)>>1;
108     if (R<=mid) return get_after(k<<1,l,mid,L,R,x);
109     else if (L>mid) return get_after(k<<1|1,mid+1,r,L,R,x);
110     else return min(get_after(k<<1|1,mid+1,r,mid+1,R,x),get_after(k<<1,l,mid,L,mid,x));
111 }
112  
113 int main(){
114     freopen("sj.txt","r",stdin);
115     freopen("me.txt","w",stdout);
116     int k;
117     scanf("%d%d",&n,&m);
118     for (int i=1;i<=n;i++){scanf("%d",&a[i]);build(i,a[i]);}
119     for (int i=1;i<=m;i++){
120         scanf("%d%d%d",&opt,&l,&r);
121         if (opt!=3)scanf("%d",&k);
122         switch(opt){
123             case 1:printf("%d\n",get_rank(1,1,n,l,r,k)+1);break;
124             case 2:printf("%d\n",get_num(l,r,k-1));break;
125             case 3:change(l,r);a[l]=r;break;
126             case 4:printf("%d\n",get_pre(1,1,n,l,r,k));break;
127             case 5:printf("%d\n",get_after(1,1,n,l,r,k));break;
128         }
129     }
130 }

 

【BZOJ3196】Tyvj 1730 二逼平衡树

标签:

原文地址:http://www.cnblogs.com/wuminyan/p/5152475.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!