主席树入门\模板
主席树好难,学了好久才学会,推荐个不错的博客https://blog.csdn.net/ModestCoder_/article/details/90107874 我这边就不赘述了。
AcWing 255. 第K小数
经典的主席树入门题
离散化+模板 (👇我的板子)
#include <stdio.h> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <map> #include <stack> #include <sstream> #include <set> #pragma GCC optimize(2) //#define int long long #define mm(i,v) memset(i,v,sizeof i); #define mp(a, b) make_pair(a, b) #define pi acos(-1) #define fi first #define se second //你冷静一点,确认思路再敲!!! using namespace std; typedef long long ll; typedef pair<int, int > PII; priority_queue< PII, vector<PII>, greater<PII> > que; stringstream ssin; // ssin << string while ( ssin >> int) const int N = 1e5 + 5, M = 1e4 + 5, mod = 1e9 + 9, INF = 0x3f3f3f3f; int n, m; int a[N]; vector<int> nums; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();} return x*f; } struct node { int l, r; int cnt; }tr[N * 4 + N * 17]; int root[N], idx; int find(int x) { return lower_bound(nums.begin(), nums.end(), x) - nums.begin(); } int build(int l, int r) { int p = ++idx; if (l == r) return p; int mid = l + r >> 1; tr[p].l = build(l, mid); tr[p].r = build(mid + 1, r); return p; } int insert(int p, int l, int r, int x) { int q = ++idx; tr[q] = tr[p]; if (l == r) { tr[q].cnt++; return q; } int mid = l + r >> 1; if (x <= mid) tr[q].l = insert(tr[p].l, l, mid, x); else tr[q].r = insert(tr[p].r, mid + 1, r, x); tr[q].cnt = tr[tr[q].l].cnt + tr[tr[q].r].cnt; return q; } int query(int q, int p, int l, int r, int k) { if (l == r) return r; int cnt = tr[tr[q].l].cnt - tr[tr[p].l].cnt; int mid = l + r >> 1; if (k <= cnt) return query(tr[q].l, tr[p].l, l, mid, k); else return query(tr[q].r, tr[p].r, mid + 1, r, k - cnt); } int main() { n = read(); m = read(); for (int i = 1; i <= n; ++i) { a[i] = read(); nums.push_back(a[i]); } sort(nums.begin(), nums.end()); nums.erase(unique(nums.begin(), nums.end()), nums.end()); root[0] = build(0, nums.size() - 1); for (int i = 1; i <= n; ++i) root[i] = insert(root[i - 1], 0, nums.size() - 1, find(a[i])); while (m--) { int l, r, k; l = read(); r = read(); k = read(); printf("%d\n", nums[query(root[r], root[l - 1], 0, nums.size() - 1, k)]); } // system("pause"); return 0; }
牛客、换个角度思考
原题链接https://ac.nowcoder.com/acm/problem/19427
可以离线下来用树状数组维护,也可以直接上主席树
离线+树状数组:
#include <stdio.h> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <map> #include <stack> #include <sstream> #include <set> #pragma GCC optimize(2) //#define int long long #define mm(i,v) memset(i,v,sizeof i); #define mp(a, b) make_pair(a, b) #define pi acos(-1) #define fi first #define se second //你冷静一点,确认思路再敲!!! using namespace std; typedef long long ll; typedef pair<int, int > PII; priority_queue< PII, vector<PII>, greater<PII> > que; stringstream ssin; // ssin << string while ( ssin >> int) const int N = 2e5 + 5, M = 2e5 + 5, mod = 1e9 + 9, INF = 0x3f3f3f3f; int n, m; pair<int, int>a[N]; ll tr[N]; vector<int> vec[N]; map<pair<int, PII>, ll>q; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();} return x*f; } struct node { int x, l, r, id; }list[N]; bool cmp1(node a, node b) { return a.x < b.x; } bool cmp2(node a, node b) { return a.id < b.id; } int lowbit(int x) { return x & -x; } void add(int x, ll y) { for (int i = x; i <= n; i += lowbit(i)) { tr[i] += y; } } ll sum(int x) { int ans = 0; for (int i = x; i > 0; i -= lowbit(i)) ans += tr[i]; return ans; } int main() { n = read(); m = read(); for (int i = 1; i <= n; ++i) { int x; x = read(); a[i] = {x, i}; } for (int i = 1; i <= m; ++i) { list[i].l = read(); list[i].r = read(); list[i].x = read(); list[i].id = i; } sort(a + 1, a + 1 + n); sort(list + 1, list + 1 + m, cmp1); ll now = 1; for (int i = 1; i <= m; ++i) { while (now <= n && a[now].first <= list[i].x) { add(a[now].second, 1); now++; } q[mp(list[i].x, mp(list[i].l, list[i].r))] = sum(list[i].r) - sum(list[i].l - 1); } sort(list + 1, list + 1 + m, cmp2); for (int i = 1; i <= m; ++i) { printf("%lld\n", q[mp(list[i].x, mp(list[i].l, list[i].r))]); } // system("pause"); return 0; }
主席树:
直接套模板就行
#include <stdio.h> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <map> #include <stack> #include <sstream> #include <set> #pragma GCC optimize(2) //#define int long long #define mm(i,v) memset(i,v,sizeof i); #define mp(a, b) make_pair(a, b) #define pi acos(-1) #define fi first #define se second //你冷静一点,确认思路再敲!!! using namespace std; typedef long long ll; typedef pair<int, int > PII; priority_queue< PII, vector<PII>, greater<PII> > que; stringstream ssin; // ssin << string while ( ssin >> int) const int N = 1e5 + 5, M = 1e4 + 5, mod = 1e9 + 9, INF = 0x3f3f3f3f; int n, m; int a[N]; vector<int> nums; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();} return x*f; } struct node { int l, r; int cnt; }tr[N * 4 + N * 17]; int root[N], idx; int build(int l, int r) { int p = ++idx; if (l == r) return p; int mid = l + r >> 1; tr[p].l = build(l, mid); tr[p].r = build(mid + 1, r); return p; } int insert(int p, int l, int r, int x) { int q = ++idx; tr[q] = tr[p]; if (l == r) { tr[q].cnt++; return q; } int mid = l + r >> 1; if (x <= mid) tr[q].l = insert(tr[p].l, l, mid, x); else tr[q].r = insert(tr[p].r, mid + 1, r, x); tr[q].cnt = tr[tr[q].l].cnt + tr[tr[q].r].cnt; return q; } int query(int q, int p, int l, int r, int k) { if (l == r) return tr[q].cnt - tr[p].cnt; int cnt = tr[tr[q].l].cnt - tr[tr[p].l].cnt; int mid = l + r >> 1; if (k <= mid) return query(tr[q].l, tr[p].l, l, mid, k); else return cnt + query(tr[q].r, tr[p].r, mid + 1, r, k); } int main() { n = read(); m = read(); for (int i = 1; i <= n; ++i) { a[i] = read(); } root[0] = build(0, N); for (int i = 1; i <= n; ++i) root[i] = insert(root[i - 1], 0, N, a[i]); while (m--) { int l, r, k; l = read(); r = read(); k = read(); printf("%d\n", query(root[r], root[l - 1], 0, N, k)); } // system("pause"); return 0; }