5 1 2 3 4 5 3 2 2 4 2 1 3 6 2 2 4 2
3 4
求区间第k大数,http://www.cnblogs.com/zig-zag/archive/2013/04/18/3027707.html 参考这篇博客,然后看2013年集训队XHR论文。吧
解法:操作分三种,
1. 加入一个数,
2. 删除一个数,
3. 询问答案在左区间还是又区间
方法:
二分询问的答案是什么。
对于初始数字,变为插入操作
按操作的时间顺序排列各个操作,对于修改操作拆为删除和加入操作
:1 删除之前插入的数字,2. 加入新的数字
接下来分治二分答案:
对于mid,如果插入或者删除的数字<=mid那么应该放到左区间,并且用树状数组(其他数据结构也行)
维护前X个位置有多少个数字在左边。
对于询问:如果l,r区间在左边的数字>=k那么答案在左边,否则答案在右边,并且更新K,k=k-这个区间去左边的数字个数
当low =high的时候,说明low就是答案了,只要更新询问还在low,low之间的答案即可。
复杂度分析:分治的深度是log(S)s是数据的范围。
每个询问每次被分到左边或者右边,会有log(s)次操作。每个插入或者删除也是。
但是要用树状数组维护多少个数字在左边,要log(n)次更新或者查询。
复杂度是n*log(s)*log(n)
#include<iostream> #include<cstring> #include<algorithm> #include<cstdio> #include<vector> using namespace std; #define maxn 300007 int tree[maxn]; void add(int p,int n){ for(;p<maxn;p+=p&(-p)) tree[p]+=n; } int query(int p){ int ans = 0; for(;p>0;p-=p&(-p)) ans += tree[p]; return ans; } struct Node{ int l,r,k,ty,ans; }; Node p[maxn]; int id1[maxn],id2[maxn]; void CDQ(int L,int R,int low,int high){ if(R < L) return ; if(low == high ){ for(;L<=R;L++){ p[id1[L]].ans = low; } return ; } int mid = (low+high)/2,l=L,r=R,k,u; for(int i = L;i <= R; i++){ u = id1[i]; if(p[u].ty == 2){ k = query(p[u].r) - query(p[u].l-1); if(k >= p[u].k) id2[l++] = u; else { p[u].k -= k; id2[r--] = u; } } else if(p[u].k <= mid){ add(p[u].l,p[u].ty); id2[l++] = u; } else id2[r--] = u; } for(int i = L; i <= R; i++){ u = id1[i]; if(p[u].ty != 2 && p[u].k <= mid) add(p[u].l,-p[u].ty); } for(k=L;k<l;k++) id1[k] = id2[k]; for(r=R;k<=R;k++) id1[k] = id2[r--]; CDQ(L,l-1,low,mid); CDQ(l,R,mid+1,high); } int num[maxn]; int main(){ int n,q,t,cnt; memset(tree,0,sizeof(tree)); while(scanf("%d",&n)!=EOF){ for(cnt=0;cnt<n;cnt++){ scanf("%d",&p[cnt].k); p[cnt].ty = 1; p[cnt].l = cnt+1; num[cnt+1] = p[cnt].k; } scanf("%d",&q); int ty,l,v; for(int i = 0;i < q; i++,cnt++){ scanf("%d",&p[cnt].ty); if(p[cnt].ty == 1){ scanf("%d%d",&l,&v); p[cnt].ty = -1; p[cnt].k = num[l]; p[cnt].l = l; cnt++; num[l] = v; p[cnt].ty = 1; p[cnt].k = v; p[cnt].l = l; } else { scanf("%d%d%d",&p[cnt].l,&p[cnt].r,&p[cnt].k); } } for(int i = 0;i < cnt; i++) id1[i] = i; CDQ(0,cnt-1,0,1000000000); for(int i = 0;i < cnt; i++){ if(p[i].ty == 2) printf("%d\n",p[i].ans); } } return 0; }