【線段樹套平衡樹】BZOJ 3196

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



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章