标签:顺序 pac root nlogn 持久 模拟 nod scanf 输入
首先请求出:
? 长度为n的序列
? m次询问全局第k小
做法:
? 画一棵(权值)线段树手动模拟,请记住此过程
之后,请思考;
? 长度为n的序列
? m次询问区间[l, r]中第k小值
? 值域 ±1e9
? n≤2e5 , m≤2e5
做法: 可持久化线段树
用 [1, r]建得的线段树 - [1, l-1]建得的线段树 (即把这两颗形状一样的线段树上的每个节点的权值相减), 得到的即为区间[l, r]建得的线段树, 这样之后,我们就可以求出(这棵线段树)全局第k小值,而这个值也就是区间[l, r]的第k小值
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAX 200000+99
int n, m;
struct da
{
int n,a,k;//输入顺序n,原数据a,离散化之后数据k
}a[MAX];
int ys[MAX];//da数组和原数的映射关系
bool cmp1(da x, da xxx) {
return x.a < xxx.a ;//用于离散化
}
bool cmp2(da x, da xxx) {
return x.n < xxx.n ;
}
int root[MAX];//保存森林中的各个根节点 //时间戳?
int nodecnt;//所有节点的数量
struct tree{
int sum;
int lson, rson;
}tr[MAX<<5];//2n+nlogn
int build(int l, int r) {//建空树
int now = ++nodecnt;//加点
if(l == r) return now;
int mid = (l+r)>>1;
tr[now].lson = build(l, mid);
tr[now].rson = build(mid+1, r);
return now;
}
int insert(int last, int l, int r, int x) {//建权值线段树
int now = ++nodecnt;
tr[now].sum = tr[last].sum + 1;
tr[now].lson = tr[last].lson , tr[now].rson = tr[last].rson;//先继承上一棵树再说
if(l == r) return now;
int mid = (l+r)>>1;
if(x <= mid) tr[now].lson = insert(tr[last].lson , l, mid, x);
else tr[now].rson = insert(tr[last].rson , mid+1, r, x);
return now;
}
int query(int ltree, int rtree, int l, int r, int k) {//同时跳
if(l == r) return l;
int mid = (l+r)>>1;
int tmp = tr[tr[rtree].lson ].sum - tr[tr[ltree].lson ].sum ;
if(tmp >= k) return query(tr[ltree].lson , tr[rtree].lson , l, mid, k);
else return query(tr[ltree].rson , tr[rtree].rson , mid+1, r, k-tmp);
}
int main() {
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++) scanf("%d",&a[i].a ), a[i].n = i;
sort(a+1, a+1+n, cmp1);
int tot = 0;
for(int i = 1; i <= n; i++) {
a[i].k = ++tot;
ys[tot] = a[i].a ;
while(a[i+1].a == a[i].a) a[++i].k = tot;
}
sort(a+1, a+1+n, cmp2);
// for(int i = 1; i <= n; i++) printf("\n lsh : %d\n",a[i].k );
root[0] = build(1,n);
for(int i = 1;i <= n; i++)//边加点边建树
root[i] = insert(root[i-1], 1, n, a[i].k) ;
int ans, l, r, k;
for(int i = 1; i <= m; i++) {
scanf("%d%d%d", &l, &r, &k);
ans = query(root[l-1], root[r], 1, n, k);
printf("%d\n", ys[ans]);
}
}
标签:顺序 pac root nlogn 持久 模拟 nod scanf 输入
原文地址:https://www.cnblogs.com/tyner/p/11253785.html