Acwing
洛谷
一种船新的数据结构,可以保存多代信息的线段树。
具体思路很简单:每次单点修改(这里只涉及单点修改主席树,区间修改很难维护),树中只有一条 log 长度的路径上信息有影响,所以我们新建一条链记录更改后的路径,把这条路径用指针的方法连回 上一个版本 的线段树。
然后每个版本都会对应一个根节点 r o o t [ i ] root[i] root[i] ,我们只需要从对应版本根节点遍历这颗树,就能获得对应版本的信息了。
对于此类问题的区间 [ l , r ] [l,r] [l,r] 询问,往往会涉及到前缀和的应用,如果 r o o t [ r ] root[r] root[r] 版本的树信息减去 r o o t [ l ] root[l] root[l] 版本的是可行的不影响的,显然具有前缀和性质。我们可以由此处理区间问题。
C o d e : Code: Code:
具体细节就是一些指针的运用比较独特。
#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
#define mem(a,b) memset(a,b,sizeof a)
#define cinios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define debug(x) cout<<"target is "<<x<<endl
#define forr(a,b,c) for(int a=b;a<=c;a++)
#define all(a) a.begin(),a.end()
#define oper(a) operator<(const a& ee)const
#define endl "\n"
#define ul (u << 1)
#define ur (u << 1 | 1)
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e5 + 10, M = 100010, MM = 110;
int INF = 0x3f3f3f3f, mod = 1e9 + 7;
ll LNF = 0x3f3f3f3f3f3f3f3f;
int n, m, k;
int a[N];
vector<int> vec;//离散化
int find(int x) {
return lower_bound(all(vec), x) - vec.begin() + 1;
}
struct tree
{
int l, r;//主席树不会记录区间端点,存的是指针指向左右结点
int cnt;//存数出现的个数
}tr[N * 25];
int idx, root[N];
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 update(int pre, int l, int r, int x) {
int p = ++idx;
tr[p] = tr[pre]; tr[p].cnt++;//p代继承上一代的信息
if (l == r)return p;
int mid = l + r >> 1;
//但自己那条更改的路径还是要保存连接,链状,对应更改指针即可
if (x <= mid)tr[p].l = update(tr[pre].l, l, mid, x);
else tr[p].r = update(tr[pre].r, mid + 1, r, x);
return p;
}
int query(int p, int pre, int l, int r, int k) {
if (l == r)return r;
int x = tr[tr[p].l].cnt - tr[tr[pre].l].cnt;
//具有前缀和性质
int mid = l + r >> 1;
if (k <= x)return query(tr[p].l, tr[pre].l, l, mid, k);
return query(tr[p].r, tr[pre].r, mid + 1, r, k - x);
}
void solve() {
int que;
cin >> n >> que;
forr(i, 1, n) {
cin >> a[i];
vec.push_back(a[i]);
}
sort(all(vec));
vec.erase(unique(all(vec)), vec.end());
m = vec.size();
root[0] = build(1, m);
for (int i = 1; i <= n; i++)//迭代
root[i] = update(root[i - 1], 1, m, find(a[i]));
while (que--)
{
int l, r, k;
cin >> l >> r >> k;
int t = query(root[r], root[l - 1], 1, m, k);
cout << vec[t - 1] << endl;
}
}
signed main() {
cinios;
int T = 1;
forr(t, 1, T) {
solve();
}
return 0;
}
/*
*/