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
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
树套树
线段树套平衡树(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 ",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("! "); 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 ",Qrk(x,y,w,1,n,1)+1); 152 break; 153 } 154 case 2:{ 155 x=read();y=read();w=read(); 156 printf("%d ",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 ",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 ",res); 177 break; 178 } 179 } 180 } 181 return 0; 182 }