Bzoj 1901 Dynamic Rankings
来源:互联网 发布:unity3d 热力图 编辑:程序博客网 时间:2024/04/29 15:19
【题意】
Description
给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改变后的a继续回答上面的问题。你需要编一个这样的程序,从输入文件中读入序列a,然后读入一系列的指令,包括询问指令和修改指令。对于每一个询问指令,你必须输出正确的回答。 第一行有两个正整数n(1≤n≤10000),m(1≤m≤10000)。分别表示序列的长度和指令的个数。第二行有n个数,表示a[1],a[2]……a[n],这些数都小于10^9。接下来的m行描述每条指令,每行的格式是下面两种格式中的一种。 Q i j k 或者 C i t Q i j k (i,j,k是数字,1≤i≤j≤n, 1≤k≤j-i+1)表示询问指令,询问a[i],a[i+1]……a[j]中第k小的数。C i t (1≤i≤n,0≤t≤10^9)表示把a[i]改变成为t。
Input
对于每一次询问,你都需要输出他的答案,每一个输出占单独的一行。
Output
Sample Input
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
Sample Output
6
HINT
20%的数据中,m,n≤100; 40%的数据中,m,n≤1000; 100%的数据中,m,n≤10000。
【解题方法】动态第K大,主席树套树状数组。首先静态主席树这个东西其实比较好懂,就是对于每个前缀[1,1],[1,2]....[1,n]都建一颗线段树,将数据离散化后,在线段树中统计区间内所有值出现的次数,每一个线段树都是相同的形态,那么这样我们得到一个很好的性质,这些线段树可以“相减”,假设当前查询的是区间[l,r]内第k大的值,那么我们用前缀[1, r]这个线段树和前缀[1, l-1]这颗线段树通过相减加上二分就可以找到答案。由于相邻两颗线段树最多只有logn个节点不同,我们没有必要完全新建一颗线段树,只需要把相同的结点用指针指一下就行,然后新建logn个结点,这样一来时空复杂度为n*logn。
对于动态查询的主席树,如果修改一个点的值,我们肯定不能修改所有包含这个点的线段树,时间复杂度无法承受。
那么我们就可以套上树状数组,个人感觉这里比较难懂。
树状数组的每个节点都是一颗线段树,但这棵线段树不再保存每个前缀的信息了,而是由树状数组的sum函数计算出这个前缀的信息,那么显而易见这棵线段树保存的是辅助数组S的值,即S=A[i-lowbit+1]+...+A[i],其中A[i]表示值为i的元素出现的次数。
那么对于每次修改,我们要修改树状数组上的logn棵树,对于每棵树,我们要修改logn个结点,所以时空复杂度为
O((n+q)*logn*logn),由于这道题n比较大,查询次数q比较小,所以我们可以初始时建立一颗静态的主席树,树状数组只保存每次修改的信息,那么时空复杂度降为了O(n*logn+q*logn*logn)。
【参考BLOG1】 http://blog.csdn.net/u014664226/article/details/47839973【参考BLOG2】 http://www.cnblogs.com/kuangbin/p/3308118.html
【AC 代码】
////BZOJ 1901//Created by just_sort 2016/8/22//All Rights Reserved//#include <vector>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;const int maxn = 60000+100;const int maxm = maxn*40;int n,q,m,tot,a[maxn];int T[maxn];vector<int>xs;int use[maxn],S[maxn];int getid(int x){ return lower_bound(xs.begin(),xs.end(),x)-xs.begin();}struct Q{ int l,r,k; int ty; Q(int ll,int rr,int kk,int ii):l(ll),r(rr),k(kk),ty(ii) {} Q() {}} query[10010];int lson[maxm],rson[maxm],c[maxm];int Build(int l,int r){ int root=tot++; c[root]=0; if(l!=r) { int mid=(l+r)/2; lson[root]=Build(l,mid); rson[root]=Build(mid+1,r); } return root;}int Insert(int root,int pos,int val){ int newroot=tot++,tmp=newroot; int l=0,r=m-1; c[newroot]=c[root]+val; while(l<r) { int mid=(l+r)/2; if(pos<=mid) { lson[newroot]=tot++,rson[newroot]=rson[root]; newroot=lson[newroot],root=lson[root]; r=mid; } else { lson[newroot]=lson[root],rson[newroot]=tot++; newroot=rson[newroot],root=rson[root]; l=mid+1; } c[newroot]=c[root]+val; } return tmp;}int lowbit(int x){ return x&-x;}void add(int x,int pos,int val){ while(x<=n) { S[x]=Insert(S[x],pos,val); x+=lowbit(x); }}int getsum(int x){ int ret=0; while(x) { ret+=c[lson[use[x]]]; x-=lowbit(x); } return ret;}int querykth(int left,int right,int k){ int left_root=T[left-1],right_root=T[right]; int l=0,r=m-1; for(int i=right; i; i-=lowbit(i)) use[i]=S[i]; for(int i=left-1; i; i-=lowbit(i)) use[i]=S[i]; while(l<r) { int mid=(l+r)/2; int temp=getsum(right)-getsum(left-1)+c[lson[right_root]]-c[lson[left_root]]; if(temp>=k){ r=mid; for(int i=left-1; i; i-=lowbit(i)) use[i]=lson[use[i]]; for(int i=right; i; i-=lowbit(i)) use[i]=lson[use[i]]; left_root=lson[left_root]; right_root=lson[right_root]; } else{ l=mid+1; k-=temp; for(int i=left-1; i; i-=lowbit(i)) use[i]=rson[use[i]]; for(int i=right; i; i-=lowbit(i)) use[i]=rson[use[i]]; left_root=rson[left_root]; right_root=rson[right_root]; } } return l;}int main(){ while(scanf("%d%d",&n,&q)!=EOF) { tot=m=0; xs.clear(); for(int i=1; i<=n; i++){ scanf("%d",&a[i]); xs.push_back(a[i]); } char op[10]; for(int i=0; i<q; i++){ scanf("%s",op); if(op[0]=='Q'){ query[i].ty=0; scanf("%d%d%d",&query[i].l,&query[i].r,&query[i].k); }else{ query[i].ty=1; scanf("%d%d",&query[i].l,&query[i].r); xs.push_back(query[i].r); } } sort(xs.begin(),xs.end()); xs.resize(unique(xs.begin(),xs.end())-xs.begin()); m = xs.size(); T[0]=Build(0,m-1); for(int i=1; i<=n; i++) T[i]=Insert(T[i-1],getid(a[i]),1); for(int i=1; i<=n; i++) S[i]=T[0]; for(int i=0; i<q; i++){ if(query[i].ty==0) printf("%d\n",xs[querykth(query[i].l,query[i].r,query[i].k)]); else{ add(query[i].l,getid(a[query[i].l]),-1); add(query[i].l,getid(query[i].r),1); a[query[i].l]=query[i].r; } } } return 0;}
- bzoj-1901 Dynamic Rankings
- [BZOJ 1901]Dynamic Rankings
- Bzoj 1901 Dynamic Rankings
- BZOJ 1901 Dynamic Rankings
- BZOJ 1901 Zju2112 Dynamic Rankings
- 【BZOJ 1901】 Zju2112 Dynamic Rankings
- BZOJ 1901 Zju2112 Dynamic Rankings
- bzoj 1901: Zju2112 Dynamic Rankings
- 树套树 Dynamic Rankings 动态排名 BZOJ 1901
- [BZOJ]1901: Zju2112 Dynamic Rankings 主席树
- bzoj 1901: Zju2112 Dynamic Rankings(树套树)
- BZOJ 1901 Dynamic Rankings 主席树
- 【主席树】【bzoj 1901】: Zju2112 Dynamic Rankings
- 【主席树】BZOJ 1901 Dynamic Rankings
- Bzoj 1901 Zju2112 Dynamic Rankings(树状数组+主席树)
- BZOJ 1901 Zju 2112 Dynamic Rankings 带修改主席树
- [bzoj]-1901-Zju2112 Dynamic Rankings-可持久化线段树
- 【BZOJ 1901】 Zju2112 Dynamic Rankings|树状数组套主席树
- Linux下安装mysql并用c语言连接
- android 码源分析
- Spring MVC 的http请求处理过程
- nyoj1291不是匹配
- Aandroid_action
- Bzoj 1901 Dynamic Rankings
- Glide 源码解析
- [leetcode]168. Excel Sheet Column Title -- JavaScript 代码
- 我X,你不会Google么?
- Android开发全面的工具下载地址
- 使用_beginthread创建线程
- 记阿里一面二面
- 传统javabean与spring中的bean的区别
- iphone6(s)、6(s)p屏幕适配遇到的坑