luogu3834 【模板】可持久化线段树1(主席树)
关键字:线段树 可持久化
线段树:当版本(即对应的原序列的区间[1,r])一定时,每个节点的left,right下标为值域,值为其对应的原序列区间[1,r]中元素大小在值域中的元素个数。
可持久化:新版本(对应原序列[1,r])在旧版本(对应原序列[1,r-1])上建立,从树根向树叶构造,在旧版本的节点的旁边构造新版本的节点,值为旧版本节点值+1。搜索新版本树时,从新版本树根开始搜索即可。求区间第k大,同时遍历【1,l-1】对应版本树和【1,r】对应版本树,通过节点值的差来得到第k个节点。
#include <cstdio> #include <cstring> #include <cassert> #include <cmath> #include <algorithm> using namespace std; #define LOOP(i,n) for(int i=1; i<=n; i++) #define INF 0x3f3f3f3f const int MAX_ROOT=2e5; int Seq[MAX_ROOT]; struct Node { int Cnt; Node *LeftSon, *RightSon; Node() { Cnt = 0; LeftSon = RightSon = NULL; } }; Node *_roots[MAX_ROOT]; int _vCount; int MinL, MaxR; void Init(int l, int r) { _vCount = 0; MinL = l; MaxR = r; _roots[0] = new Node(); } Node *Update(Node *prev, Node *&cur, int l, int r, int p) { cur = new Node(); *cur = *prev; cur->Cnt++; if (l == r) return cur; int mid = (r - l) / 2 + l; if (p <= mid) { if (!prev->LeftSon) prev->LeftSon = new Node(); Update(prev->LeftSon, cur->LeftSon, l, mid, p); } else { if (!prev->RightSon) prev->RightSon = new Node(); Update(prev->RightSon, cur->RightSon, mid + 1, r, p); } return cur; } int Query(Node *prev, Node *cur, int l, int r, int k) { if (l == r) return l; int prevLeft = prev->LeftSon ? prev->LeftSon->Cnt : 0, curLeft = cur->LeftSon ? cur->LeftSon->Cnt : 0; int leftCnt = curLeft - prevLeft; int mid = (r - l) / 2 + l; if (k <= leftCnt) { if (!prev->LeftSon) prev->LeftSon = new Node(); return Query(prev->LeftSon, cur->LeftSon, l, mid, k); } else { if (!prev->RightSon) prev->RightSon = new Node(); return Query(prev->RightSon, cur->RightSon, mid + 1, r, k - leftCnt); } } void Update(int r) { Update(_roots[r - 1], _roots[r], MinL, MaxR, Seq[r]); } int Query(int l, int r, int k) { return Query(_roots[l - 1], _roots[r], MinL, MaxR, k); } int main() { #ifdef _DEBUG freopen("c:\\noi\\source\\input.txt", "r", stdin); #endif int seqCnt, queryCnt, l, r, k, minL = INF, maxR = -INF; scanf("%d%d", &seqCnt, &queryCnt); LOOP(i, seqCnt) { scanf("%d", i + Seq); minL = min(Seq[i], minL); maxR = max(Seq[i], maxR); } Init(minL, maxR); LOOP(i, seqCnt) Update(i); LOOP(i, queryCnt) { scanf("%d%d%d", &l, &r, &k); printf("%d\n", Query(l, r, k)); } return 0; }