主席树(hdu2665)

来源:互联网 发布:mix2 知乎 编辑:程序博客网 时间:2024/05/20 13:18
Give you a sequence and ask you the kth big number of a inteval.

InputThe 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
OutputFor 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

由于这个是动态查询,我们开辟nlogn*n的区间显然是不可以的,我们可以发现,每一次查询的时候只是改变了一个叶节点,然后我们画图可知一条链上最多有[lgn+2]向下取整的点被改动于是我们就可以建立一颗主席树,动态开辟节点,每一个节点使用一个左右指针就可以了。
由于数据范围比较大,我们可以采用离散化,首先对数组进行排序和去重,然后再数组里面二分原数组进行更新就可以了
然后就是一大堆细节处理啦,处理不好就会像我一样wa无数遍。
具体看代码,我这份代码应该自我感觉写的比较好看的。。
update 主席树的空间大约为nlg^2n所以空间要开辟的大一些lg1e5大约在17左右,我多开一倍(1<<5)否则会re
#pragma GCC optimize("O2")#include<bits/stdc++.h>#define mid (l+(r-l)/2)#define maxn 120000 using namespace std;int b[maxn],a[maxn],sum[maxn<<5],n,m,sz=0,L[maxn<<5],R[maxn<<5];void build(int &rt,int l,int r){rt=++sz,sum[rt]=0;if(l==r) return ;build(L[rt],l,mid);build(R[rt],mid+1,r);}void update(int pr,int &rt,int l,int r,int x){rt=++sz;sum[rt]=sum[pr]+1;L[rt]=L[pr],R[rt]=R[pr];if(l==r) return ;if(x<=mid) update(L[pr],L[rt],l,mid,x);else update(R[pr],R[rt],mid+1,r,x);}int query(int pr,int rt,int l,int r,int x){if(l==r) return l;int now=sum[L[rt]]-sum[L[pr]];if(now>=x) return query(L[pr],L[rt],l,mid,x);else return query(R[pr],R[rt],mid+1,r,x-now);}int rt[maxn];int main(){int t;scanf("%d",&t);while(t--){scanf("%d%d",&n,&m);sz=0;for(int i=1;i<=n;i++)scanf("%d",&a[i]),b[i]=a[i];sort(b+1,b+n+1);int d=unique(b+1,b+n+1)-(b+1);build(rt[0],1,d);for(int i=1;i<=n;i++){int x=lower_bound(b+1,b+1+d,a[i])-b;update(rt[i-1],rt[i],1,d,x);}while(m--){int l,r,k;scanf("%d%d%d",&l,&r,&k);printf("%d\n",b[query(rt[l-1],rt[r],1,d,k)]);}}return 0;}

 

原创粉丝点击