您的位置:首页 > 其它

hdu2665主席树(可持久化线段树)

2017-08-23 16:11 239 查看
Input

The first line is the number of the test cases.

For each test case, the first line contain two integer n and m (n, m <= 100000), indicates the number of integers in the sequence and the number of the quaere.

The second line contains n integers, describe the sequence.

Each of following m lines contains three integers s, t, k.

[s, t] indicates the interval and k indicates the kth big number in interval [s, t]

Output

For each test case, output m lines. Each line contains the kth big number.

Sample Input

1

10 1

1 4 2 3 5 6 7 8 9 0

1 3 2

Sample Output
2

【题意】

t组样例,有n个数,m个询问。

m个询问中有l,r,k;

询问在[l,r]区间中,第k大的数是多少。

【解法】

将n个数离散化(假设离散化后下标为1-t)后建立一颗区间为1-t的线段树,每个[x,x]都表示离散化后下标为x的数的个数。

用主席数记录每加入一个数后该线段树的变化。

最后求[l,r]区间的第k大时

两颗差值树中  左子树的size表示比当前根小的数的个数,如果左子树size>=k就在左子树中找,否则就去右子树中找k-左子树size的值。。。。。

呃,感觉解释不清。。意会意会吧。。上代码了。。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#define N 100005
using namespace std;
int tree[N*25],lchild[N*25],rchild[N*25],root
;
int a
,b
,cnt;
map<int,int>mp;
void build(int l,int r,int root){
if(l==r){
tree[root]=0;
return;
}
int mid=l+r>>1;
build(l,mid,lchild[root]=++cnt);
build(mid+1,r,rchild[root]=++cnt);
tree[root]=tree[lchild[root]]+tree[rchild[root]];
return ;
}
void update(int last,int cur,int l,int r,int x){
tree[cur]=tree[last];
lchild[cur]=lchild[last];
rchild[cur]=rchild[last];
if(l==r){
tree[cur]++;
return;
}
int mid=l+r>>1;
if(x<=mid) update(lchild[last],lchild[cur]=++cnt,l,mid,x);
else update(rchild[last],rchild[cur]=++cnt,mid+1,r,x);
tree[cur]=tree[lchild[cur]]+tree[rchild[cur]];
return ;
}
int query(int last,int cur,int l,int r,int k){
if(l==r){
//printf("l=%d r=%d k=%d\n",l,r,k);
return l;
}
int mid=l+r>>1;
int now=tree[lchild[cur]]-tree[lchild[last]];//注意判断的是左子树的size哦
// printf("left=%d mid=%d right=%d now=%d k=%d\n",l,mid,r,now,k);
if(now>=k) return query(lchild[last],lchild[cur],l,mid,k);
else return query(rchild[last],rchild[cur],mid+1,r,k-now);
}
int main(){
int t;
scanf("%d",&t);
while(t--){
cnt=0;
mp.clear();//???
int n,m,ss=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b+1,b+n+1);
/* for(int i=1;i<=n;i++){
if(i!=n) printf("b[%d]=%d ",i,b[i]);
else printf("b[%d]=%d\n",i,b[i]);
}
*/
int t=unique(b+1,b+1+n)-b-1;//离散化
//printf("t=%d\n",t);
build(1,t,++cnt);
root[0]=1;
for(int i=1;i<=t;i++){
mp[b[i]]=i;
}
for(int i=1;i<=n;i++){
root[i]=++cnt;
update(root[i-1],root[i],1,t,mp[a[i]]);
}
while(m--){
int left,right,k;
scanf("%d%d%d",&left,&right,&k);
printf("%d\n",b[query(root[left-1],root[right],1,t,k)]);//query返回的是第k大的数离散化后的下标,所以b[query]才是原来的值
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: