Online Judge | Problem Set | Authors | Online Contests | User | ||||||
---|---|---|---|---|---|---|---|---|---|---|
Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest |
直接上主席树#include<cstdio> #include<algorithm> #include<vector> #define N 100010 using namespace std; /* 定义主席树的节点, 主席树是一坨权值线段树的剪切拼接, 每个节点的值是一个值域区间的数字出现的次数。 */ struct node { int l,r; int sum; /*l,r分别表示左右儿子的编号,于是左右儿子就是hjt[l],hjt[r] sum表示该节点的值*/ }hjt[N<<5];//对黄景泰dalao表示尊敬,, 大佬教我写代码。。。 long long org[N]; vector<long long>v; inline int GetId(long long x) { return lower_bound(v.begin(),v.end(),x)-v.begin()+1; } int cnt=0; int root[N];//记录根节点的编号 //依托上一个版本建立新的线段树。。。于是就变成主席树了 void insert(int l,int r,int pre,int &now,long long p) { hjt[++cnt]=hjt[pre];//先复制上一个版本的线段树,再修改 now=cnt; //要同步,,整了个引用 hjt[now].sum++;//新插入一个数 if(l==r) return; int mid=(l+r)>>1; //插入p,就是在线段树表示p的位置插入,,权值线段树。。权值线段树,,权值线段树 if(p<=mid) insert(l,mid,hjt[pre].l,hjt[now].l,p); else insert(mid+1,r,hjt[pre].r,hjt[now].r,p); } /* 查询给定一个区间 x~y 前缀和思想,得到某一个区间的权值线段树 L代表x-1的版本的权值线段树遍历的当前节点 R表示y的版本的权值线段树遍历的当前节点 */ long long query(int l,int r,int L,int R,int k) { if(l==r) return l; int mid=(l+r)>>1; /* 两个版本的线段树相减, 当前节点的左子树上的sum相减,得到新的线段树的左子树的sum值(前缀和思想) 得到的权值线段树的当前节点的sum就是左子树上数字的个数 */ int temp=hjt[hjt[R].l].sum-hjt[hjt[L].l].sum; if(k<=temp) return query(l,mid,hjt[L].l,hjt[R].l,k); else return query(mid+1,r,hjt[L].r,hjt[R].r,k-temp); } int main() { int n,m; int i; scanf("%d%d",&n,&m); for(i=1;i<=n;i++) { scanf("%lld",&org[i]); v.push_back(org[i]);//离散化处理 } //排序,去重 sort(v.begin(),v.end()); v.erase(unique(v.begin(),v.end()),v.end()); //依次建立一坨版本的权值线段树 for(i=1;i<=n;i++) { //以前一个版本的根节点为依托 insert(1,n,root[i-1],root[i],GetId(org[i])); } int k; for(k=1;k<=m;k++) { int r; scanf("%d",&r); printf("%lld\n",v[query(1,n,root[0],root[r],k)-1]); } return 0; } Followed by: Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator