建树:
#include <bits/stdc++.h> using namespace std; const int N=1e5+7; int n,m,sz; int root[N]/*存放根节点对应的三数组下标*/,ls[N*44]/*存放当前节点所对应的左节点三数组下标*/,rs[N*44]/*同ls*/,sum[N*44];//存放当前区间内数字的个数 //sum,rl,rs 可以整合为一个结构体 inline void update(int l,int r,int x,int &y,int v)//建树 { y=++sz;//y作为新节点下标返回给上一个节点的ls[y]/rs[y]做到更新上一节点的下标对应 sum[y]=sum[x]+1;//按照上一个结点更新新节点的sum值 if(l==r)return ; ls[y]=ls[x];rs[y]=rs[x]; //复制上一颗树的左右两节点所对应的三个数组下标同一节点的三个下标是一致的也就达到了连接节点的目的,因为rl和rs存在即可以共用之前的节点; int mid=(l+r)>>1; if(v<=mid)update(l,mid,ls[x],ls[y],v); else update(mid+1,r,rs[x],rs[y],v); }int main() { int t; scanf("%d",&t); while(t--) { sz=0; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { int x; scanf("%d",&x); update(1,n,root[i-1],root[i],x); } } }
数据离散化处理例题求区间第K大
#include <bits/stdc++.h> using namespace std; const int N=1e5+7; int n,m,sz,b[N]; int root[N]/*存放根节点对应的三数组下标*/,ls[N*44]/*存放当前节点所对应的左节点三数组下标*/,rs[N*44]/*同ls*/,sum[N*44];//存放当前区间内数字的个数 //sum,rl,rs 可以整合为一个结构体 vector<int>v; int getid(int x) { return lower_bound(v.begin(),v.end(),x)-v.begin()+1; } inline void update(int l,int r,int x,int &y,int v)//建树 { y=++sz;//y作为新节点下标返回给上一个节点的ls[y]/rs[y]做到更新上一节点的下标对应 sum[y]=sum[x]+1;//按照上一个结点更新新节点的sum值 if(l==r)return ; ls[y]=ls[x];rs[y]=rs[x]; //复制上一颗树的左右两节点所对应的三个数组下标同一节点的三个下标是一致的也就达到了连接节点的目的,因为rl和rs存在即可以共用之前的节点; int mid=(l+r)>>1; if(v<=mid)update(l,mid,ls[x],ls[y],v); else update(mid+1,r,rs[x],rs[y],v); } int query(int l,int r,int x,int y,int k) { if(l==r) return l; int xx=sum[ls[y]]-sum[ls[x]]; //比较左子树的大小和k的关系来确定寻找左子树或者右子树 int mid=(l+r)>>1; if(xx>=k) return query(l,mid,ls[x],ls[y],k); else return query(mid+1,r,rs[x],rs[y],k-xx); } int main() { cin>>n>>m; for(int i=1;i<=n;i++) { cin>>b[i]; v.push_back(b[i]); } sort(v.begin(),v.end()); v.erase(unique(v.begin(),v.end()),v.end()); for(int i=1;i<=n;i++) update(1,n,root[i-1],root[i],getid(b[i])); int x,y,k; for(int i=0;i<m;i++) { cin>>x>>y>>k; cout<<v[query(1,n,root[x-1],root[y],k)-1]<<endl; } }