[BZOJ 1901] Dynamic Rankings 【树状数组套线段树 || 线段树套线段树】

题目链接:BZOJ - 1901

题目分析

树状数组套线段树或线段树套线段树都可以解决这道题。

第一层是区间,第二层是权值。

空间复杂度和时间复杂度均为 O(n log^2 n)。

线段树比树状数组麻烦好多...我容易写错= =

代码

树状数组套线段树

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>

using namespace std;

const int MaxN = 10000 + 5, MN = 1000000015, MaxNode = 10000 * 30 * 15 + 15;

int n, m, Index, Used_Index;
int A[MaxN], Root[MaxN], Son[MaxNode][2], T[MaxNode], U[MaxN], C[MaxN];

void Add(int &x, int s, int t, int Pos, int Num) 
{
	if (x == 0) x = ++Index;
	T[x] += Num;
	if (s == t) return;
	int m = (s + t) >> 1;
	if (Pos <= m) Add(Son[x][0], s, m, Pos, Num);
	else Add(Son[x][1], m + 1, t, Pos, Num); 
}

void Change(int x, int Pos, int Num) 
{
	for (int i = x; i <= n; i += i & -i)
		Add(Root[i], 0, MN, Pos, Num);
}

int Get_Sum(int x) 
{
	int ret = 0;
	for (int i = x; i; i -= i & -i)
		ret += T[Son[U[i]][0]];
	return ret;
}

void Init_U(int x) 
{
	for (int i = x; i; i -= i & -i)
		U[i] = Root[i];
}

void Turn(int x, int f) 
{
	for (int i = x; i; i -= i & -i)
	{
		if (C[i] == Used_Index) break;
		C[i] = Used_Index;
		U[i] = Son[U[i]][f];
	}
}

int main() 
{
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++i) 
	{
		scanf("%d", &A[i]);
		Change(i, A[i], 1);
	}
	char f;
	int Pos, Num, L, R, k, Temp;
	for (int i = 1; i <= m; ++i) 
	{
		f = '-';
		while (f < 'A' || f > 'Z') f = getchar();
		if (f == 'C') 
		{
			scanf("%d%d", &Pos, &Num);
			Change(Pos, A[Pos], -1);
			A[Pos] = Num;
			Change(Pos, Num, 1);
		}
		else 
		{
			scanf("%d%d%d", &L, &R, &k);
			int l, r, mid;
			l = 0; r = MN;
			Init_U(L - 1);
			Init_U(R);
			Used_Index = 0;
			while (l < r)
			{
				mid = (l + r) >> 1;
				Temp = Get_Sum(R) - Get_Sum(L - 1);
				++Used_Index;
				if (Temp >= k) 
				{
					r = mid;
					Turn(L - 1, 0);
					Turn(R, 0);
				}
				else 
				{
					l = mid + 1;
					k -= Temp;
					Turn(L - 1, 1);
					Turn(R, 1);
				}
			}
			printf("%d
", l);
		}
	}
	return 0;
}

线段树套线段树

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>

using namespace std;

const int MaxN = 10000 + 5, MN = 1000000000 + 15, MaxNode = 10000 * 30 * 15 + 15;

int n, m, Index, Used_Index;
int A[MaxN], Root[MaxN * 4], T[MaxNode], Son[MaxNode][2], U[MaxN * 4], C[MaxN * 4];

void Add(int &x, int s, int t, int Pos, int Num) 
{
	if (x == 0) x = ++Index;
	T[x] += Num;
	if (s == t) return;
	int m = (s + t) >> 1;
	if (Pos <= m) Add(Son[x][0], s, m, Pos, Num);
	else Add(Son[x][1], m + 1, t, Pos, Num); 
}

void Change(int x, int s, int t, int Pos, int Pos_2, int Num) 
{
	Add(Root[x], 0, MN, Pos_2, Num);
	if (s == t) return;
	int m = (s + t) >> 1;
	if (Pos <= m) Change(x << 1, s, m, Pos, Pos_2, Num);
	else Change(x << 1 | 1, m + 1, t, Pos, Pos_2, Num);
}

void Init_U(int x, int s, int t, int Pos) 
{
	if (Pos >= t) 
	{
		U[x] = Root[x]; 
		return;
	}
	int m = (s + t) >> 1;
	Init_U(x << 1, s, m, Pos);
	if (Pos >= m + 1) Init_U(x << 1 | 1, m + 1, t, Pos);
}

void Turn(int x, int s, int t, int Pos, int f) 
{
	if (Pos >= t) 
	{
		if (C[x] == Used_Index) return;
		C[x] = Used_Index;
		U[x] = Son[U[x]][f];
		return;
	}
	int m = (s + t) >> 1;
	Turn(x << 1, s, m, Pos, f);
	if (Pos >= m + 1) Turn(x << 1 | 1, m + 1, t, Pos, f);
}

int Get_Sum(int x, int s, int t, int Pos) 
{
	if (Pos >= t) return T[Son[U[x]][0]];
	int ret = 0, m = (s + t) >> 1;
	ret += Get_Sum(x << 1, s, m, Pos);
	if (Pos >= m + 1) ret += Get_Sum(x << 1 | 1, m + 1, t, Pos);
	return ret; 
}

int main()  
{
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++i) 
	{
		scanf("%d", &A[i]);
		Change(1, 0, n, i, A[i], 1);
	}
	char f;
	int L, R, Pos, Num, k;
	for (int i = 1; i <= m; ++i) 
	{
		f = '-';
		while (f < 'A' || f > 'Z') f = getchar();
		if (f == 'C') 
		{
			scanf("%d%d", &Pos, &Num);
			Change(1, 0, n, Pos, A[Pos], -1);
			A[Pos] = Num;
			Change(1, 0, n, Pos, Num, 1);
		}	
		else 
		{
			scanf("%d%d%d", &L, &R, &k);
			int l, r, mid, Temp;
			Used_Index = 0;
			Init_U(1, 0, n, L - 1);
			Init_U(1, 0, n, R);
			l = 0; r = MN;
			while (l < r) 
			{
				++Used_Index;
				mid = (l + r) >> 1;
				Temp = Get_Sum(1, 0, n, R) - Get_Sum(1, 0, n, L - 1);
				if (Temp >= k) 
				{
					r = mid;
					Turn(1, 0, n, R, 0);
					Turn(1, 0, n, L - 1, 0);
				}
				else 
				{
					l = mid + 1;
					Turn(1, 0, n, R, 1);
					Turn(1, 0, n, L - 1, 1);
					k -= Temp;
				}
			}
			printf("%d
", l);
		}
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/JoeFan/p/4317275.html