【bzoj3196-二逼平衡树】线段树套平衡树
http://acm.hust.edu.cn/vjudge/problem/42297
【题目描述】
写一种数据结构,来维护一个有序数列,其中需要提供以下操作:
1.查询k在区间内的排名
2.查询区间内排名为k的值
3.修改某一位值上的数值
4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)
5.查询k在区间内的后继(后继定义为大于x,且最小的数)
【输入格式】
第一行两个数 n,m( n,m <= 50000 )表示长度为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的前驱(没有前驱输出no)
若opt=5 则为操作5,之后有三个数l,r,k 表示查询区间[l,r]内k的后继(没有后继输出no)
【输出格式】
对于操作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、序列中每个数的数据范围:[0,1e8]
2、虽然原题没有,但事实上5操作的k可能为负数
这题我在bzoj上AC,在tvoj上最后两个点TLE(然而并不知道怎么优化)。
昨天中午打了一个中午,晚上调了一个钟,今天早上又调了两个钟。。呵呵。。
我的做法是在开一棵1~n的线段树t,每个节点(管理t[x].l~t[x].r)开一棵treap,把t[x].l~t[x].r的值全部放进去。为了防止找前驱后继的时候有问题,每棵treap上先放-Inf和Inf进去。
1.表示查询k在区间[l,r]的排名:用线段树找到[l,r]所需要用到的线段树上的节点,开一个数组存起来,然后一个个区间查询比k小的数的个数。
2.表示查询区间[l,r]内排名为k的数:mn和mx存下出现过的最小和最大的数是什么。二分一个数x,然后用1的方法看x的排名。
这里注意一个问题:找的是排名<=k的最大的数。
例如:1 2 3 3 3 5,查询3的排名是3,但是如果我们要找排名为4的数,答案依然是3。
3.单点修改:顺着线段树走下去,中途所经过的点,都要在它那棵treap上del原来的数,ins新数
4.找前驱:就在线段树上先找出所有要用到的点,再一个个进去找在这棵treap树上的前驱x,取最大值。
5.找后继:同上。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 using namespace std; 6 7 const int N=50010,TN=50000*16+100,Inf=(int)1e9; 8 struct tr_node{ 9 int son[2],n,c,f,d; 10 }c[2*TN]; 11 struct xd_node{ 12 int lc,rc,l,r,root; 13 }t[2*2*N]; 14 int tl,cl,sl; 15 int w[2*N],s[2*N]; 16 17 void updata(int x) 18 { 19 if(!x) return; 20 int lc=c[x].son[0],rc=c[x].son[1]; 21 c[x].c=c[x].n+c[lc].c+c[rc].c; 22 } 23 24 void add(int d,int f) 25 { 26 cl++; 27 c[cl].f=f;c[cl].d=d; 28 c[cl].n=c[cl].c=1; 29 c[cl].son[0]=c[cl].son[1]=0; 30 if(d<c[f].d) c[f].son[0]=cl; 31 else c[f].son[1]=cl; 32 updata(f);//debug 33 } 34 35 int find_ip(int d,int id) 36 { 37 int x=t[id].root; 38 while(c[x].d!=d) 39 { 40 if(d<c[x].d) 41 { 42 if(c[x].son[0]) x=c[x].son[0]; 43 else break; 44 } 45 else 46 { 47 if(c[x].son[1]) x=c[x].son[1]; 48 else break; 49 } 50 } 51 return x; 52 } 53 54 void rotate(int x) 55 { 56 int y=c[x].f,z=c[y].f,w,r,R; 57 w=(c[y].son[0]==x) ? 1:0; 58 59 r=c[x].son[w];R=y; 60 c[R].son[1-w]=r; 61 if(r) c[r].f=R; 62 63 r=x;R=z; 64 c[R].son[(c[z].son[0]==y) ? 0:1]=r; 65 c[r].f=R; 66 67 r=y;R=x; 68 c[R].son[w]=r; 69 c[r].f=R; 70 71 updata(y); 72 updata(x); 73 } 74 75 void splay(int x,int rt,int id) 76 { 77 while(c[x].f!=rt) 78 { 79 int y=c[x].f,z=c[y].f; 80 if(z==rt) rotate(x); 81 else 82 { 83 if((c[z].son[0]==y) == (c[y].son[0]==x)) rotate(y),rotate(x); 84 else rotate(x),rotate(x); 85 } 86 } 87 if(rt==0) t[id].root=x; 88 } 89 90 void ins(int d,int id) 91 { 92 int root=t[id].root; 93 if(root==0) {add(d,0);t[id].root=cl;return;} 94 int x=find_ip(d,id); 95 if(c[x].d==d) c[x].n++; 96 else add(d,x); 97 updata(x); 98 splay(x,0,id); 99 } 100 101 int build_xd_tree(int l,int r) 102 { 103 int x=++tl; 104 t[x].l=l;t[x].r=r; 105 t[x].lc=t[x].rc=0; 106 t[x].root=0; 107 if(l<r) 108 { 109 int mid=(l+r)>>1; 110 t[x].lc=build_xd_tree(l,mid); 111 t[x].rc=build_xd_tree(mid+1,r); 112 ins(-Inf,x);ins(Inf,x); 113 for(int i=l;i<=r;i++) ins(w[i],x); 114 } 115 else ins(-Inf,x),ins(Inf,x),ins(w[t[x].l],x);//l==r 116 return x; 117 } 118 119 void find_xd_id(int x,int l,int r) 120 { 121 if(t[x].l==l && t[x].r==r) {s[++sl]=x;return;} 122 int lc=t[x].lc,rc=t[x].rc,mid=(t[x].l+t[x].r)>>1; 123 if(r<=mid) find_xd_id(lc,l,r); 124 else if(l>mid) find_xd_id(rc,l,r); 125 else find_xd_id(lc,l,mid),find_xd_id(rc,mid+1,r); 126 } 127 128 int find_qq(int d,int id) 129 { 130 int x=find_ip(d,id);splay(x,0,id);//debug splay(x,0,id) 131 if(c[x].d>=d && c[x].son[0]) 132 { 133 x=c[x].son[0]; 134 while(c[x].son[1]) x=c[x].son[1]; 135 } 136 if(c[x].d>=d) x=0; 137 return x; 138 } 139 140 int find_hj(int d,int id) 141 { 142 int x=find_ip(d,id);splay(x,0,id);//debug 143 if(c[x].d<=d && c[x].son[1]) 144 { 145 x=c[x].son[1]; 146 while(c[x].son[0]) x=c[x].son[0]; 147 } 148 if(c[x].d<=d) x=0; 149 return x; 150 } 151 152 void del(int d,int id) 153 { 154 int x=find_ip(d,id);splay(x,0,id); 155 if(c[x].n>=2) {c[x].n--;return;} 156 int x0=find_qq(d,id); 157 int x1=find_hj(d,id); 158 splay(x0,0,id); 159 splay(x1,x0,id); 160 c[x1].son[0]=0; 161 updata(x1); 162 } 163 164 void change(int x,int p,int d) 165 { 166 if(t[x].l==t[x].r) 167 { 168 del(w[p],x);ins(d,x); 169 return; 170 } 171 int lc=t[x].lc,rc=t[x].rc,mid=(t[x].l+t[x].r)>>1; 172 if(p<=mid) change(lc,p,d); 173 else change(rc,p,d); 174 del(w[p],x);ins(d,x); 175 } 176 177 int find_rk(int d,int id)//the number of all that <d 178 { 179 int root=t[id].root; 180 int x=find_qq(d,id); 181 splay(x,0,id); 182 return c[c[x].son[0]].c-1+c[x].n; 183 } 184 185 int opt1(int k,int l,int r) 186 { 187 int ans=0; 188 sl=0;find_xd_id(1,l,r); 189 for(int j=1;j<=sl;j++) 190 ans+=find_rk(k,s[j]); 191 return ans+1; 192 } 193 194 int minn(int x,int y){return x<y ? x:y;} 195 int maxx(int x,int y){return x>y ? x:y;} 196 197 int find_rank(int k) 198 { 199 int ans=0; 200 for(int i=1;i<=sl;i++) 201 ans+=find_rk(k,s[i]); 202 return ans+1; 203 } 204 205 int main() 206 { 207 freopen("a.in","r",stdin); 208 freopen("a.out","w",stdout); 209 int n,m; 210 scanf("%d%d",&n,&m); 211 tl=0;cl=0; 212 int mn=Inf,mx=-Inf; 213 for(int i=1;i<=n;i++) 214 { 215 scanf("%d",&w[i]); 216 mn=minn(mn,w[i]); 217 mx=maxx(mx,w[i]); 218 } 219 build_xd_tree(1,n); 220 for(int i=1;i<=m;i++) 221 { 222 int k,l,r,pos,opt; 223 scanf("%d",&opt); 224 if(opt!=3) scanf("%d%d%d",&l,&r,&k); 225 else scanf("%d%d",&pos,&k); 226 if(opt==1) 227 { 228 int ans=0; 229 sl=0;find_xd_id(1,l,r); 230 printf("%d\n",find_rank(k)); 231 } 232 if(opt==2) 233 { 234 sl=0;find_xd_id(1,l,r); 235 int ll=mn,rr=mx; 236 while(ll!=rr) 237 { 238 int mid=(ll+rr+1)>>1; 239 int now=find_rank(mid); 240 if(now<=k) ll=mid;//注意 241 else rr=mid-1; 242 } 243 printf("%d\n",ll); 244 } 245 if(opt==3) 246 { 247 change(1,pos,k); 248 w[pos]=k; 249 mn=minn(mn,k); 250 mx=maxx(mx,k); 251 } 252 if(opt==4) 253 { 254 int ans=-Inf; 255 sl=0;find_xd_id(1,l,r); 256 for(int j=1;j<=sl;j++) ans=maxx(ans,c[find_qq(k,s[j])].d); 257 if(ans!=-Inf) printf("%d\n",ans); 258 else printf("no\n"); 259 } 260 if(opt==5) 261 { 262 int ans=Inf; 263 sl=0;find_xd_id(1,l,r); 264 for(int j=1;j<=sl;j++) ans=minn(ans,c[find_hj(k,s[j])].d); 265 if(ans!=Inf) printf("%d\n",ans); 266 else printf("no\n"); 267 } 268 } 269 return 0; 270 }