[BZOJ 1901] Dynamic Rankings 【树状数组套线段树 || 线段树套线段树】
题目链接:BZOJ - 1901
题目分析
树状数组套线段树或线段树套线段树都可以解决这道题。
第一层是区间,第二层是权值。
空间复杂度和时间复杂度均为 O(n log^2 n)。
线段树比树状数组麻烦好多...我容易写错= =
代码
树状数组套线段树
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | #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\n" , l); } } return 0; } |
线段树套线段树
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | #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\n" , l); } } return 0; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)