标签:poi rank false 第k小 pac std mes 子节点 否则
学了主席树,用来求区间上的第k小
写一下自己整理后的模板
#include<bits/stdc++.h>
using namespace std;
//求区间第k小
const int maxn = 500010;
struct node{
int v,lc,rc;
}T[maxn * 21];
int n,m;
int root[maxn];
int e;
void insert(int pre,int cur,int pos,int l,int r){
if(l == r){
T[cur].v = T[pre].v + 1;
return;
}
int mid = (l + r) >> 1;
if(pos <=mid ){
T[cur].lc = ++e; //新建左子结点
T[cur].rc = T[pre].rc; //保留右子节点
insert(T[pre].lc,T[cur].lc,pos,l,mid); //insert左
}else{
T[cur].rc = ++e; //新建右子节点
T[cur].lc = T[pre].lc; //保留左子结点
insert(T[pre].rc,T[cur].rc,pos,mid+1,r); //insert右
}
T[cur].v = T[T[cur].lc].v + T[T[cur].rc].v;
}
int query(int ql,int qr,int l,int r,int k){
if(l == r) return l;
int mid = (l + r) >> 1;
int sum = T[T[qr].lc].v - T[T[ql].lc].v;
if(sum >= k) return query(T[ql].lc,T[qr].lc,l,mid,k);
else return query(T[ql].rc,T[qr].rc,mid+1,r,k-sum); //这个ql.rc 和 qr.lc什么时候用老是搞不清楚
}
int main(){
int x,y,d,k;
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>d;
root[i] = ++e;
insert(root[i-1],root[i],d,1,n);
}
while(m--){
cin>>x>>y>>k;
cout<<query(root[x-1],root[y],1,n,k)<<endl;
}
return 0;
}
当数据比较大时(比如这道题的1e9那么大),就需要先离散化了。
#include<bits/stdc++.h>
using namespace std;
//sp3946
const int maxn = 500010;
struct node{
int v,lc,rc;
}T[maxn * 21];
int n,m;
int root[maxn];
int ranks[maxn];
int e;
struct A{
int x,idx;
bool operator < (const A &temp)const{
return x < temp.x;
}
}a[maxn];
void insert(int pre,int cur,int pos,int l,int r){
if(l == r){
T[cur].v = T[pre].v + 1;
return;
}
int mid = (l + r) >> 1;
if(pos <=mid ){
T[cur].lc = ++e; //新建左子结点
T[cur].rc = T[pre].rc; //保留右子节点
insert(T[pre].lc,T[cur].lc,pos,l,mid); //insert左
}else{
T[cur].rc = ++e; //新建右子节点
T[cur].lc = T[pre].lc; //保留左子结点
insert(T[pre].rc,T[cur].rc,pos,mid+1,r); //insert右
}
T[cur].v = T[T[cur].lc].v + T[T[cur].rc].v;
}
int query(int ql,int qr,int l,int r,int k){
if(l == r) return l;
int mid = (l + r) >> 1;
int sum = T[T[qr].lc].v - T[T[ql].lc].v;
if(sum >= k) return query(T[ql].lc,T[qr].lc,l,mid,k);
else return query(T[ql].rc,T[qr].rc,mid+1,r,k-sum); //这个ql.rc 和 qr.lc什么时候用老是搞不清楚
}
int main(){
int x,y,d,k;
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i].x;
a[i].idx = i;
}
sort(a+1,a+n+1);
for(int i=1;i<=n;i++) ranks[a[i].idx] = i;
for(int i=1;i<=n;i++){
root[i] = ++e;
insert(root[i-1],root[i],ranks[i],1,n);
}
while(m--){
cin>>x>>y>>k;
cout<<query(root[x-1],root[y],1,n,k)<<endl;
}
return 0;
}
因为这个数 在区间(l,r)上出现的次数最多为1次或者0次
所以用主席树维护每个数出现的次数,然后query查询时 左子树出现次数>goal就往左走、右子树出现次数>goal就往右走,否则return 0,最后直到叶节点(l==r)就会找到目标数
#include<bits/stdc++.h>
using namespace std;
//poi2014
const int maxn = 500001;
struct node{
int v,lc,rc;
}T[maxn * 21];
int n,m;
int root[maxn];
int e;
void insert(int pre,int cur,int pos,int l,int r){
if(l == r){
T[cur].v = T[pre].v + 1;
return;
}
int mid = (l + r) >> 1;
if(pos <=mid ){
T[cur].lc = ++e; //新建左子结点
T[cur].rc = T[pre].rc; //保留右子节点
insert(T[pre].lc,T[cur].lc,pos,l,mid); //insert左
}else{
T[cur].rc = ++e; //新建右子节点
T[cur].lc = T[pre].lc; //保留左子结点
insert(T[pre].rc,T[cur].rc,pos,mid+1,r); //insert右
}
T[cur].v = T[T[cur].lc].v + T[T[cur].rc].v;
}
int goal;
//对于读入的区间,取长度后进行询问
//如果左子树大于mid的就继续往左走
//右子树大于mid的就继续往右走,否则return 0
int query(int ql,int qr,int l,int r){ //这里 T数组两棵树相减 为什么左子树相减 右子树相减 没搞懂
if(l == r) return l;
int mid = (l + r) >> 1;
if(T[T[qr].lc].v - T[T[ql].lc].v > goal) return query(T[ql].lc,T[qr].lc,l,mid);
else if(T[T[qr].rc].v - T[T[ql].rc].v > goal) return query(T[ql].rc,T[qr].rc,mid+1,r);
return 0; //没有就返回0
}
int main(){
int x,y,d;
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>d;
root[i] = ++e;
insert(root[i-1],root[i],d,1,n);
}
while(m--){
cin>>x>>y;
goal = y-x+1>>1;
cout<<query(root[x-1],root[y],1,n)<<endl;
}
return 0;
}
标签:poi rank false 第k小 pac std mes 子节点 否则
原文地址:https://www.cnblogs.com/fisherss/p/12229528.html