终于开始看主席树了
主席树就是对数组[1...n](建设排序去重后一共有m个不同的数字)的每个前缀[1...i]建立一颗线段树,记录从1到i出现在(1-m)的数有多少个,比如对于i=x,cnt[x]表示出现在(1-m)一共有多少个,他的左孩子lson表示前缀1-x出现在(1-m/2)中出现的次数。
关于主席树详细的讲解请看主席树读书笔记
下面附上poj2104主席树代码,原来用划分树写过
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=100010;
const int maxm=maxn*30;
int n,q,m;
int a[maxn];
struct TREE
{
int order[maxn];
int T[maxm],cnt[maxm],lson[maxm],rson[maxm];
int num;
void init()
{
for(int i=1;i<=n;i++)order[i]=a[i];
sort(order+1,order+1+n);
m=unique(order+1,order+1+n)-order-1;
num=0;
}
int build(int l,int r)
{
int root=num++;
cnt[root]=0;
if(l==r)return root;
int mid=(l+r)>>1;
lson[root]=build(l,mid);
rson[root]=build(mid+1,r);
return root;
}
int update(int root,int pos,int val)
{
int newroot=num++,tmp=newroot;
cnt[newroot]=cnt[root]+val;
int l=1,r=m;
while(l<r)
{
int mid=(l+r)>>1;
if(pos<=mid)
{
r=mid;
lson[newroot]=num++;rson[newroot]=rson[root];
newroot=lson[newroot],root=lson[root];
}
else
{
l=mid+1;
lson[newroot]=lson[root],rson[newroot]=num++;
newroot=rson[newroot],root=rson[root];
}
cnt[newroot]=cnt[root]+val;
}
return tmp;
}
int query(int left,int right,int k)
{
int l=1,r=m;
while(l<r)
{
int mid=(l+r)>>1;
if(cnt[lson[left]]-cnt[lson[right]]>=k)
{
r=mid;
left=lson[left];
right=lson[right];
}
else
{
l=mid+1;
k-=(cnt[lson[left]]-cnt[lson[right]]);
left=rson[left];
right=rson[right];
}
}
return l;
}
}tree;
int main()
{
while(scanf("%d%d",&n,&q)!=EOF)
{
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
tree.init();
tree.T[n+1]=tree.build(1,m);
for(int i=n;i>0;i--)
{
int pos=lower_bound(tree.order+1,tree.order+1+m,a[i])-tree.order;
tree.T[i]=tree.update(tree.T[i+1],pos,1);
}
while(q--)
{
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",tree.order[tree.query(tree.T[l],tree.T[r+1],k)]);
}
}
return 0;
}
2761跟上面是一样的
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=100010;
const int maxm=maxn*20;
int a[maxn],order[maxn],cnt[maxm],lson[maxm],rson[maxm],T[maxm];
int n,m,q,num;
void init()
{
num=0;
for(int i=1;i<=n;i++)order[i]=a[i];
sort(order+1,order+1+n);
m=unique(order+1,order+1+n)-order-1;
}
int find(int x)
{
return lower_bound(order+1,order+1+m,x)-order;
}
int build(int l,int r)
{
int root=num++;
cnt[root]=0;
if(l!=r)
{
int mid=(l+r)>>1;
lson[root]=build(l,mid);
rson[root]=build(mid+1,r);
}
return root;
}
int update(int root,int pos,int val)
{
int newroot=num++,tmp=num-1;
int l=1,r=m;
cnt[newroot]=cnt[root]+val;
while(l<r)
{
int mid=(l+r)>>1;
if(pos<=mid)
{
r=mid;
lson[newroot]=num++,rson[newroot]=rson[root];
newroot=lson[newroot];root=lson[root];
}
else
{
l=mid+1;
rson[newroot]=num++,lson[newroot]=lson[root];
newroot=rson[newroot],root=rson[root];
}
cnt[newroot]=cnt[root]+val;
}
return tmp;
}
int query(int left,int right,int k)
{
int l=1,r=m;
while(l<r)
{
int mid=(l+r)>>1;
int tmp=cnt[lson[right]]-cnt[lson[left]];
if(tmp>=k)
{
r=mid;
right=lson[right];
left=lson[left];
}
else
{
k-=tmp;
l=mid+1;
right=rson[right];
left=rson[left];
}
}
return l;
}
int main()
{
while(scanf("%d%d",&n,&q)!=EOF)
{
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
init();
T[0]=build(1,m);
for(int i=1;i<=n;i++)
T[i]=update(T[i-1],find(a[i]),1);
while(q--)
{
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",order[query(T[l-1],T[r],k)]);
}
}
return 0;
}