主席树真的神奇!
直接给我经常用的板子吧
静态主席树:点这里 -----点这个也不错
动态主席树:点这里
/*
静态主席树(查询区间第 k 大)
/*
在STL中unique函数是一个去重函数, unique的功能是去除相邻的重复元素(只保留一个),
其实它并不真正把重复的元素删除,是把重复的元素移到后面去了,
然后依然保存到了原数组中,然后 返回去重后最后一个元素的地址,去重后最后一个元素的下一个地址
因为unique去除的是相邻的重复元素,所以一般用之前都会要排一下序。
*/
/*
n 是大小!然后m是离散化后的个数
ls[],rs[] 分别表示的就是左儿子跟右儿子
c[] 记入的就是数字出现的次数
你要算区间[x,y],那么就是temp = c[ls[T[y]]-c[ls[T[x-1]] 然后判断跟k的大小 利用的就是前缀和的思想
tot 表示的就是所有的节点
*/
const int maxn=1e5+10;
const int N=maxn*30;
int n,q,m,tot;
int a[maxn],t[maxn];
int T[N],ls[N],rs[N],c[N];
void init()
{
for(int i=1;i<=n;i++)
t[i]=a[i];
sort(t+1,t+n+1);
m=unique(t+1,t+n+1)-t-1;
}
int build(int l,int r)
{
int root=tot++;
c[root]=0;
if(l!=r)
{
int mid=(l+r)/2;
ls[root]=build(l,mid);
rs[root]=build(mid+1,r);
}
return root;
}
int hashh(int x)
{
return lower_bound(t+1,t+1+m,x)-t; //返回下标
}
int update(int root,int pos,int val,int l,int r)
{
int newroot=tot++,tmp=newroot;
c[newroot]=c[root]+val;
if(l==r) return 1;
int mid=(l+r)/2;
if(pos<=mid)
{
ls[newroot]=tot;rs[newroot]=rs[root];
update(ls[root],pos,val,l,mid);
}
else
{
rs[newroot]=tot;ls[newroot]=ls[root];
update(rs[root],pos,val,mid+1,r);
}
return tmp;
}
int query(int l,int r,int x,int y,int k) // 查找区间 X,y
{
int mid=(l+r)/2;
if(l==r) return l;
int sum=c[ls[y]]-c[ls[x]];
if(sum>=k)
{
query(l,mid,ls[x],ls[y],k);
}
else
query(mid+1,r,rs[x],rs[y],k-sum);
}
void solve(){
scanf("%d%d",&n,&q);
tot=0;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
init();
T[0]=build(1,m);
//cout<<T[0]<<endl;
for(int i=1;i<=n;i++)
{
int pos=hashh(a[i]);
T[i]=update(T[i-1],pos,1,1,m);
//cout<<T[i]<<" ";
}
//cout<<endl;
while(q--)
{
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",t[query(1,m,T[l-1],T[r],k)]);
}
}
静态主席树第一题
裸题:Hdu Kth number---- 洛谷3834
题目传送门:POJ2104
题意: 给你n,m,让你去求区间第k大的数字
我的理解: 直接看我套的板子吧!
AC代码
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<string>
#include<set>
#define sa(t) scanf("%d",&t)
#define SA(t) scanf("%lld", %t)
#define PF(t) printf("%lld",t)
#define pf(t) printf("%d", t)
#define PFF(t) printf("%lld\n",t)
#define pff(t) printf("%d\n", t)
typedef long long int ll;
using namespace std;
const int maxn=1e5+10;
const int N=maxn*30;
int n,q,m,tot;
int a[maxn],t[maxn];
int T[N],ls[N],rs[N],c[N];
void init()
{
for(int i=1;i<=n;i++)
t[i]=a[i];
sort(t+1,t+n+1);
m=unique(t+1,t+n+1)-t-1;
}
int build(int l,int r)
{
int root=tot++;
c[root]=0;
if(l!=r)
{
int mid=(l+r)/2;
ls[root]=build(l,mid);
rs[root]=build(mid+1,r);
}
return root;
}
int hashh(int x)
{
return lower_bound(t+1,t+1+m,x)-t; //返回下标
}
int update(int root,int pos,int val,int l,int r)
{
int newroot=tot++,tmp=newroot;
c[newroot]=c[root]+val;
if(l==r) return 1;
int mid=(l+r)/2;
if(pos<=mid)
{
ls[newroot]=tot;rs[newroot]=rs[root];
update(ls[root],pos,val,l,mid);
}
else
{
rs[newroot]=tot;ls[newroot]=ls[root];
update(rs[root],pos,val,mid+1,r);
}
return tmp;
}
int query(int l,int r,int x,int y,int k) // 查找区间 X,y
{
int mid=(l+r)/2;
if(l==r) return l;
int sum=c[ls[y]]-c[ls[x]];
if(sum>=k)
{
query(l,mid,ls[x],ls[y],k);
}
else
query(mid+1,r,rs[x],rs[y],k-sum);
}
void solve(){
scanf("%d%d",&n,&q);
tot=0;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
init();
T[0]=build(1,m);
//cout<<T[0]<<endl;
for(int i=1;i<=n;i++)
{
int pos=hashh(a[i]);
T[i]=update(T[i-1],pos,1,1,m);
//cout<<T[i]<<" ";
}
//cout<<endl;
while(q--)
{
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",t[query(1,m,T[l-1],T[r],k)]);
}
}
int main(){
int cass;
cass = 1;
// scanf("%d",&cass);
while(cass--){
solve();
}
}