zoukankan      html  css  js  c++  java
  • [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;
    }
    

      

  • 相关阅读:
    Linux下C程序的反汇编【转】
    数据在内存中的存储方式( Big Endian和Little Endian的区别 )(x86系列则采用little endian方式存储数据)【转】
    linux arm的存储分布那些事之一【转】
    linux arm mmu基础【转】
    linux 进程内存解析【转】
    如何更方便的查看Linux内核代码的更新记录【转】
    设备树解析【转】
    分析内核源码,设备树【转】
     Meltdown论文翻译【转】
    device tree --- #address-cells and #size-cells property【转】
  • 原文地址:https://www.cnblogs.com/JoeFan/p/4317275.html
Copyright © 2011-2022 走看看