主席树好难,学了好久才学会,推荐个不错的博客https://blog.youkuaiyun.com/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;
}
本文深入探讨了主席树的数据结构,提供了详细的代码实现,并通过AcWing255题目的解析,展示了如何运用主席树解决第K小数问题。同时,文章对比了使用树状数组和主席树的不同实现方式。
424

被折叠的 条评论
为什么被折叠?



