【线段树套平衡树】BZOJ 3196

来源:互联网 发布:ip广播的网络设置 编辑:程序博客网 时间:2024/05/22 03:13

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

今天又写了一次这题,感觉熟练的许多。

注意,root数组开四倍,因为线段树最多有4*N的节点级别。

Succ操作当平衡树中当前节点为空时返回INF,Pred操作返回0.

平衡树空间可适当开大些,N(logN+2).

详见代码

#include<cstdio>#include<cstring>#include<algorithm>#define fo(i,a,b) for (int i = a;i <= b;i ++)#define INF 100000001using namespace std;const int maxn = 50010;const int maxp = maxn*2*18;int N,M,tot;int A[maxn],root[maxn*4],left[maxp],right[maxp],size[maxp],key[maxp];inline void L_rotate(int &t){int k = right[t];right[t] = left[k];left[k] = t;size[k] = size[t];size[t] = size[left[t]] + size[right[t]] + 1;t = k;}inline void R_rotate(int &t){int k = left[t];left[t] = right[k];right[k] = t;size[k] = size[t];size[t] = size[left[t]] + size[right[t]] + 1;t = k;}inline void maintain(int &t,bool flag){if (!flag){if (size[left[left[t]]] > size[right[t]])R_rotate(t);else if (size[right[left[t]]] > size[right[t]])L_rotate(left[t]), R_rotate(t);else return;} else {if (size[right[right[t]]] > size[left[t]])L_rotate(t);else if (size[left[right[t]]] > size[left[t]])R_rotate(right[t]), L_rotate(t);else return;}maintain(left[t],0);maintain(right[t],1);maintain(t,0);maintain(t,1);}inline void Insert(int &t,int v){if (!t){t = ++ tot;key[t] = v;size[t] = 1;return; }size[t] ++;if (v < key[t]) Insert(left[t],v);else Insert(right[t],v);maintain(t,v >= key[t]);}inline void Maketree(int z,int l,int r){fo(i,l,r) Insert(root[z],A[i]);if (l == r) return;int mid = (l + r) >> 1;Maketree(z*2,l,mid);Maketree(z*2+1,mid+1,r);}inline int Delete(int &t,int v){size[t] --;if ((key[t] == v) || (v < key[t] && !left[t]) || (v > key[t] && !right[t])){int ret = key[t];if (!left[t] || !right[t]) t = left[t] + right[t];else key[t] = Delete(left[t],v+1);return ret;}if (v < key[t]) return Delete(left[t],v);else return Delete(right[t],v);}inline void Modify(int z,int l,int r,int p,int v){Delete(root[z],A[p]);Insert(root[z],v);if (l == r) return;int mid = (l + r) >> 1;if (p <= mid) Modify(z*2,l,mid,p,v);else Modify(z*2+1,mid+1,r,p,v);}inline int Rank(int t,int v){if (!t) return 0;if (v <= key[t]) return Rank(left[t],v);else return size[left[t]] + 1 + Rank(right[t],v);}inline int Getrank(int z,int l,int r,int x,int y,int v){if (x <= l && r <= y) return Rank(root[z],v);int ret = 0;int mid = (l + r) >> 1;if (x <= mid) ret += Getrank(z*2,l,mid,x,y,v);if (y > mid) ret += Getrank(z*2+1,mid+1,r,x,y,v);return ret;}inline int Pred(int t,int v){if (!t) return 0;if (v <= key[t]) return Pred(left[t],v);else {int ret = Pred(right[t],v);if (!ret) ret = key[t];return ret;}}inline int Getpred(int z,int l,int r,int x,int y,int v){if (x <= l && r <= y) return Pred(root[z],v);int ret = 0;int mid = (l + r) >> 1;if (x <= mid) ret = max(ret,Getpred(z*2,l,mid,x,y,v));if (y > mid) ret = max(ret,Getpred(z*2+1,mid+1,r,x,y,v));return ret;}inline int Succ(int t,int v){if (!t) return INF;if (v >= key[t]) return Succ(right[t],v);else {int ret = Succ(left[t],v);if (ret == INF) ret = key[t];return ret;}}inline int Getsucc(int z,int l,int r,int x,int y,int v){if (x <= l && r <= y) return Succ(root[z],v);int ret = INF;int mid = (l + r) >> 1;if (x <= mid) ret = min(ret,Getsucc(z*2,l,mid,x,y,v));if (y > mid) ret = min(ret,Getsucc(z*2+1,mid+1,r,x,y,v));return ret;}int main(){freopen("tree.in","r",stdin);freopen("tree.out","w",stdout);scanf("%d%d",&N,&M);fo(i,1,N) scanf("%d",&A[i]);Maketree(1,1,N);while (M--){int op,l,r,k;scanf("%d%d%d",&op,&l,&r);if (op != 3) scanf("%d",&k);if (op == 1) printf("%d\n",Getrank(1,1,N,l,r,k)+1);if (op == 2) {int L,R,ans;L = 0; R = INF;while (L <= R){int mid = (L + R) >> 1;if (Getrank(1,1,N,l,r,mid)+1 <= k){ans = mid;L = mid + 1;} else R = mid - 1;}printf("%d\n",ans);}if (op == 3) {Modify(1,1,N,l,r);A[l] = r;}if (op == 4) printf("%d\n",Getpred(1,1,N,l,r,k));if (op == 5) printf("%d\n",Getsucc(1,1,N,l,r,k));}return 0;}



0 0
原创粉丝点击