bzoj3196 二逼平衡树 树套树(线段树套Treap)
Tyvj 1730 二逼平衡树
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 4697 Solved: 1798
[Submit][Status][Discuss]
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
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
4
3
4
9
HINT
1.n和m的数据范围:n,m<=50000
2.序列中每个数的数据范围:[0,1e8]
3.虽然原题没有,但事实上5操作的k可能为负数
Source
题解:
这道题目的第二个操作没什么办法,唉,记得当时有log n 的算法的,现在只有log^2n的算法,o( ̄ヘ ̄o#)
线段树套平衡树吧,这里选的是Treap
1 #include<cstring> 2 #include<cmath> 3 #include<algorithm> 4 #include<iostream> 5 #include<cstdio> 6 7 #define N 200007 8 #define M 4000007 9 #define inf 2000000007 10 using namespace std; 11 inline int read() 12 { 13 int x=0,f=1;char ch=getchar(); 14 while(ch>'9'||ch<'0'){if (ch=='-') f=-1;ch=getchar();} 15 while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} 16 return x*f; 17 } 18 19 int n,m,ans,sz; 20 int ls[M],rs[M],rnd[M],val[M],siz[M],ct[M]; 21 int root[N],a[N]; 22 23 inline int rand() 24 { 25 static int seed=2333; 26 return seed=(int)((((seed^998244353)+19260817ll)*19890604ll)%1000000007); 27 } 28 void update(int p){siz[p]=siz[ls[p]]+siz[rs[p]]+ct[p];} 29 void rturn(int &p){int t=ls[p];ls[p]=rs[t];rs[t]=p;siz[t]=siz[p];update(p);p=t;} 30 void lturn(int &p){int t=rs[p];rs[p]=ls[t];ls[t]=p;siz[t]=siz[p];update(p);p=t;} 31 void ins(int &p,int z) 32 { 33 if (!p) 34 { 35 p=++sz; 36 siz[p]=ct[p]=1; 37 val[p]=z; 38 rnd[p]=rand(); 39 return; 40 } 41 siz[p]++; 42 if (z==val[p])ct[p]++; 43 else if (z<val[p]) 44 { 45 ins(ls[p],z); 46 if (rnd[ls[p]]<rnd[p]) rturn(p); 47 } 48 else 49 { 50 ins(rs[p],z); 51 if (rnd[rs[p]]<rnd[p]) lturn(p); 52 } 53 } 54 void del(int &p,int x) 55 { 56 if (p==0) return; 57 if (val[p]==x) 58 { 59 if (ct[p]>1) ct[p]--,siz[p]--;//如果有多个直接减一即可。 60 else 61 { 62 if (ls[p]==0||rs[p]==0) p=ls[p]+rs[p];//单节点或者空的话直接儿子移上来或者删去即可。 63 else if (rnd[ls[p]]<rnd[rs[p]]) rturn(p),del(p,x); 64 else lturn(p),del(p,x); 65 } 66 } 67 else if (x>val[p]) siz[p]--,del(rs[p],x); 68 else siz[p]--,del(ls[p],x); 69 } 70 void build(int p,int l,int r,int x,int z) 71 { 72 ins(root[p],z); 73 if (l==r) return; 74 int mid=(l+r)>>1; 75 if(x<=mid)build(p<<1,l,mid,x,z); 76 else build(p<<1|1,mid+1,r,x,z); 77 } 78 void get_rank_sec(int p,int z) 79 { 80 if (!p) return;//没有不需要。 81 if (z==val[p]) ans+=siz[ls[p]]; 82 else if (z<val[p]) get_rank_sec(ls[p],z); 83 else 84 { 85 ans+=siz[ls[p]]+ct[p]; 86 get_rank_sec(rs[p],z); 87 } 88 } 89 void get_rank_fir(int p,int l,int r,int x,int y,int z) 90 { 91 if (l==x&&r==y) 92 { 93 get_rank_sec(root[p],z); 94 return; 95 } 96 int mid=(l+r)>>1; 97 if (y<=mid) get_rank_fir(p<<1,l,mid,x,y,z); 98 else if (x>mid) get_rank_fir(p<<1|1,mid+1,r,x,y,z); 99 else get_rank_fir(p<<1,l,mid,x,mid,z),get_rank_fir(p<<1|1,mid+1,r,mid+1,y,z); 100 } 101 void mid_to_find_index(int x,int y,int z) 102 { 103 int l=0,r=inf,res; 104 while(l<=r) 105 { 106 int mid=(l+r)>>1; 107 ans=1;get_rank_fir(1,1,n,x,y,mid); 108 if(ans<=z){l=mid+1;res=mid;} 109 else r=mid-1; 110 } 111 printf("%d\n",res); 112 } 113 void modify(int p,int l,int r,int x,int yl,int xz) 114 { 115 del(root[p],yl); 116 ins(root[p],xz); 117 if (l==r) return; 118 int mid=(l+r)>>1; 119 if (x<=mid)modify(p<<1,l,mid,x,yl,xz); 120 else modify(p<<1|1,mid+1,r,x,yl,xz); 121 } 122 void find_before_sec(int p,int z) 123 { 124 if (!p) return; 125 if (val[p]<z) 126 { 127 ans=max(ans,val[p]); 128 find_before_sec(rs[p],z); 129 } 130 else find_before_sec(ls[p],z); 131 } 132 void find_before_fir(int p,int l,int r,int x,int y,int z) 133 { 134 if (l==x&&r==y) 135 { 136 find_before_sec(root[p],z); 137 return; 138 } 139 int mid=(l+r)>>1; 140 if (y<=mid) find_before_fir(p<<1,l,mid,x,y,z); 141 else if (x>mid) find_before_fir(p<<1|1,mid+1,r,x,y,z); 142 else find_before_fir(p<<1,l,mid,x,mid,z),find_before_fir(p<<1|1,mid+1,r,mid+1,y,z); 143 } 144 void find_after_sec(int p,int z) 145 { 146 if(!p)return; 147 if(val[p]>z) 148 { 149 ans=min(val[p],ans); 150 find_after_sec(ls[p],z); 151 } 152 else find_after_sec(rs[p],z); 153 } 154 void find_after_fir(int p,int l,int r,int x,int y,int z) 155 { 156 if (l==x&&r==y) 157 { 158 find_after_sec(root[p],z); 159 return; 160 } 161 int mid=(l+r)>>1; 162 if (y<=mid) find_after_fir(p<<1,l,mid,x,y,z); 163 else if (x>mid) find_after_fir(p<<1|1,mid+1,r,x,y,z); 164 else find_after_fir(p<<1,l,mid,x,mid,z),find_after_fir(p<<1|1,mid+1,r,mid+1,y,z); 165 } 166 int main() 167 { 168 n=read(),m=read(); 169 for (int i=1;i<=n;i++) 170 a[i]=read(),build(1,1,n,i,a[i]); 171 while(m--) 172 { 173 int flag=read(),x,y,k; 174 switch(flag) 175 { 176 case 1:x=read(),y=read(),k=read(),ans=1,get_rank_fir(1,1,n,x,y,k),printf("%d\n",ans);break; 177 case 2:x=read(),y=read(),k=read(),mid_to_find_index(x,y,k);break; 178 case 3:x=read(),y=read(),modify(1,1,n,x,a[x],y),a[x]=y;break; 179 case 4:x=read(),y=read(),k=read(),ans=0,find_before_fir(1,1,n,x,y,k),printf("%d\n",ans);break; 180 case 5:x=read(),y=read(),k=read(),ans=inf,find_after_fir(1,1,n,x,y,k),printf("%d\n",ans);break; 181 } 182 } 183 }