题目链接:http://poj.org/problem?id=2104
主席树入门题目,主席树其实就是可持久化权值线段树,rt[i]维护了前i个数中第i大(小)的数出现次数的信息,通过查询两棵树的差即可得到第k大(小)元素。
#include<cstdio> #include<vector> #include<algorithm> using namespace std; #define lson(i) node[i].lson #define rson(i) node[i].rson const int maxn=100005; int rt[maxn]; struct Node { int lson,rson,val; }node[maxn*30]; int tot; void push_up(int i) { node[i].val=node[lson(i)].val+node[rson(i)].val; } int build(int l,int r) { int i=++tot; if (l==r) node[i].val=0; else { int mid=(l+r)/2; lson(i)=build(l,mid); rson(i)=build(mid+1,r); push_up(i); } return i; } int rebuild(int k,int x,int i,int nowl,int nowr) { int th=++tot; lson(th)=lson(i); rson(th)=rson(i); node[th].val=node[i].val; if (nowl==nowr) node[th].val+=x; else { int mid=(nowl+nowr)/2; if (k<=mid) node[th].lson=rebuild(k,x,lson(i),nowl,mid); else node[th].rson=rebuild(k,x,rson(i),mid+1,nowr); push_up(th); } return th; } int query(int rt1,int rt2,int k,int nowl,int nowr) { if (nowl==nowr) return nowl; int left=node[lson(rt2)].val-node[lson(rt1)].val; int mid=(nowl+nowr)/2; if (left>=k) return query(lson(rt1),lson(rt2),k,nowl,mid); else return query(rson(rt1),rson(rt2),k-left,mid+1,nowr); } int a[maxn]; vector<int> ls; int main() { int n,m; scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&a[i]); ls.clear(); for (int i=1;i<=n;i++) ls.push_back(a[i]); sort(ls.begin(),ls.end()); ls.erase(unique(ls.begin(),ls.end()),ls.end()); rt[0]=build(1,n); for (int i=1;i<=n;i++) { int j=lower_bound(ls.begin(),ls.end(),a[i])-ls.begin(); rt[i]=rebuild(j+1,1,rt[i-1],1,n); } for (int i=1;i<=m;i++) { int l,r,k; scanf("%d%d%d",&l,&r,&k); printf("%d\n",ls[query(rt[l-1],rt[r],k,1,n)-1]); } return 0; }
时间: 2024-10-04 08:31:49