zoukankan      html  css  js  c++  java
  • [BZOJ 3196] 213平衡树 【线段树套set + 树状数组套线段树】

    题目链接:BZOJ - 3196

    题目分析

    区间Kth和区间Rank用树状数组套线段树实现,区间前驱后继用线段树套set实现。

    为了节省空间,需要离线,先离散化,这样需要的数组大小可以小一些,可以卡过128MB = =

    嗯就是这样,代码长度= =我写了260行......Debug了n小时= =

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <set>
    #include <map>
    using namespace std;
    
    const int MaxN = 50000 + 5, MaxM = 50000 + 5, MN = 100000 + 15, INF = 999999999, MaxNode = 8000000 + 15;
    
    int n, m, Index, Used_Index, Top, Hash_Index;
    int A[MaxN], Root[MaxN], T[MaxNode], Son[MaxNode][2], U[MaxN], C[MaxN], Que[MaxN + MaxM], TR[MaxN + MaxM];
    
    struct Query
    {
    	int f, L, R, k, Num, Pos;
    } Q[MaxM];
    
    map<int, int> M;
    
    multiset<int> S[MaxN * 4];
    multiset<int>::iterator It;
    
    inline int gmin(int a, int b) {return a < b ? a : b;}
    inline int gmax(int a, int b) {return a > b ? a : b;}
    
    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);
    }
    
    void Add_S(int x, int s, int t, int Pos, int Num) 
    {
    	S[x].insert(Num);
    	if (s == t) return;
    	int m = (s + t) >> 1;
    	if (Pos <= m) Add_S(x << 1, s, m, Pos, Num);
    	else Add_S(x << 1 | 1, m + 1, t, Pos, Num);
    }
    
    void Del_S(int x, int s, int t, int Pos, int Num)
    {
    	S[x].erase(S[x].find(Num));
    	if (s == t) return;
    	int m = (s + t) >> 1;
    	if (Pos <= m) Del_S(x << 1, s, m, Pos, Num);
    	else Del_S(x << 1 | 1, m + 1, t, Pos, Num);
    }
     
    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 Get_LSum(int x) 
    {
    	int ret = 0;
    	for (int i = x; i; i -= i & -i)
    		ret += T[Son[U[i]][0]];
    	return ret;
    }
    
    int Before(int x, int s, int t, int l, int r, int Num)
    {
    	int ret;
    	if (l <= s && r >= t)
    	{
    		It = S[x].end();
    		It--;
    		if (*It < Num) return *It;
    		It = S[x].begin();
    		if (*It >= Num) return -INF;
    		It = S[x].lower_bound(Num);
    		It--;
    		return *It;
    	}
    	int m = (s + t) >> 1;
    	ret = -INF;
    	if (l <= m) ret = gmax(ret, Before(x << 1, s, m, l, r, Num));
    	if (r >= m + 1) ret = gmax(ret, Before(x << 1 | 1, m + 1, t, l, r, Num));
    	return ret;
    }
    
    int After(int x, int s, int t, int l, int r, int Num)
    {
    	int ret;
    	if (l <= s && r >= t)
    	{
    		It = S[x].upper_bound(Num);
    		if (It == S[x].end()) return INF;
    		else return *It;
    	}
    	int m = (s + t) >> 1;
    	ret = INF;
    	if (l <= m) ret = gmin(ret, After(x << 1, s, m, l, r, Num));
    	if (r >= m + 1) ret = gmin(ret, After(x << 1 | 1, m + 1, t, l, r, Num));
    	return ret;
    }
    
    int main() 
    {
    	scanf("%d%d", &n, &m);
    	Top = 0; Index = 0;
    	for (int i = 1; i <= n; ++i) 
    	{
    		scanf("%d", &A[i]);
    		Que[++Top] = A[i];
    	}
    	for (int i = 1; i <= m; ++i) 
    	{
    		scanf("%d", &Q[i].f);
    		switch (Q[i].f) 
    		{
    			case 1 : 
    				scanf("%d%d%d", &Q[i].L, &Q[i].R, &Q[i].Num);
    				break;
    			case 2 : 
    				scanf("%d%d%d", &Q[i].L, &Q[i].R, &Q[i].k);
    				break;
    			case 3 :
    				scanf("%d%d", &Q[i].Pos, &Q[i].Num);
    				break;
    			case 4 :
    				scanf("%d%d%d", &Q[i].L, &Q[i].R, &Q[i].Num);
    				break;
    			case 5 :
    				scanf("%d%d%d", &Q[i].L, &Q[i].R, &Q[i].Num);
    				break;
    		}
    		if (Q[i].f != 2) Que[++Top] = Q[i].Num;
    	}
    	sort(Que + 1, Que + Top + 1);
    	Hash_Index = 0;
    	for (int i = 1; i <= Top; ++i) 
    	{
    		if (i > 1 && Que[i] == Que[i - 1]) continue;
    		M[Que[i]] = ++Hash_Index;
    		TR[Hash_Index] = Que[i];
    	}
    	for (int i = 1; i <= n; ++i) 
    	{
    		A[i] = M[A[i]];
    		Change(i, A[i], 1);
    		Add_S(1, 1, n, i, A[i]);
    	}
    	int L, R, Pos, Num, k, Temp, l, r, mid; 
    	for (int i = 1; i <= m; ++i) 
    	{
    		if (Q[i].f != 2) Q[i].Num = M[Q[i].Num];
    		switch (Q[i].f) 
    		{
    			case 1 : 
    				L = Q[i].L; R = Q[i].R; Num = Q[i].Num;
    				Used_Index = 0;
    				Init_U(L - 1);
    				Init_U(R);
    				Temp = 0;
    				l = 0; r = MN;
    				while (l < r) 
    				{
    					++Used_Index;
    					mid = (l + r) >> 1;
    					if (Num <= mid) 
    					{
    						r = mid;
    						Turn(L - 1, 0);
    						Turn(R, 0);
    					}
    					else 
    					{
    						Temp += Get_LSum(R) - Get_LSum(L - 1);
    						l = mid + 1;
    						Turn(L - 1, 1);
    						Turn(R, 1);
    					}
    				}
    				printf("%d
    ", Temp + 1);
    				break;
    
    			case 2 : 
    				L = Q[i].L; R = Q[i].R; k = Q[i].k;
    				Init_U(L - 1);
    				Init_U(R);
    				Used_Index = 0;
    				Temp = 0;
    				l = 0; r = MN;
    				while (l < r)
    				{
    					++Used_Index;
    					mid = (l + r) >> 1;
    					Temp = Get_LSum(R) - Get_LSum(L - 1);
    					if (Temp >= k) 
    					{
    						r = mid;
    						Turn(L - 1, 0);
    						Turn(R, 0);
    					}
    					else 
    					{
    						l = mid + 1;
    						Turn(L - 1, 1);
    						Turn(R, 1);
    						k -= Temp; 
    					}
    				}
    				printf("%d
    ", TR[l]);
    				break;
    			
    			case 3 :
    				Pos = Q[i].Pos; Num = Q[i].Num;
    				Change(Pos, A[Pos], -1);
    				Del_S(1, 1, n, Pos, A[Pos]);
    				A[Pos] = Num;
    				Change(Pos, Num, 1);
    				Add_S(1, 1, n, Pos, Num);
    				break;
    				
    			case 4 :
    				L = Q[i].L; R = Q[i].R; Num = Q[i].Num;
    				printf("%d
    ", TR[Before(1, 1, n, L, R, Num)]);
    				break;
    			
    			case 5 :
    				L = Q[i].L; R = Q[i].R; Num = Q[i].Num;
    				printf("%d
    ", TR[After(1, 1, n, L, R, Num)]);
    				break;
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    Win10删除anaconda重装
    anaconda python no module named 'past'的解决方法
    detectMultiScale 读取冲突的一个解决方法
    [原] Android快速开发框架-AndroidFine,GitHub开源
    [原] Android 自定义View 密码框 例子
    [原]发布一个jQuery提示框插件,Github开源附主站,jquery.tooltips.js
    [原] Jenkins Android 自动打包配置
    [原] Android性能优化方法
    阿里云9折推荐码:0LGVW2
    [原]那些年整理的Linux常用命令,简单明了
  • 原文地址:https://www.cnblogs.com/JoeFan/p/4318950.html
Copyright © 2011-2022 走看看