• [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;
    }
    

      

  • 相关阅读:
    经典网页设计:漂亮的个人作品集网站设计欣赏【中篇】
    引领网页设计潮流的优秀网页作品赏析《第二季》
    Chance – 功能强大的 JavaScript 随机数生成类库
    设计前沿:16款扁平风格 iOS 7 图标设计
    TwentyTwenty – 使用 jQuery 实现图片对比功能
    未来的 Web:九个不可思议的 WebGL 应用试验
    推荐25个帮助你提高技能的 CSS3 实战教程
    经典网页设计:顶尖的个人作品集网站设计欣赏【上篇】
    Smint – 用于单页网站制作的 jQuery 导航菜单插件
    关注经典:CSS Awards 获奖网站作品赏析《第一季》
  • 原文地址:https://www.cnblogs.com/JoeFan/p/4317275.html
Copyright © 2020-2023  润新知