您需要寫一種數據結構(可參考題目標題),來維護一個有序數列,其中需要提供以下操作:
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 100000001
using 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;
}