[bzoj1901][Zju2112]Dynamic Rankings【树套树】【树状数组】【线段树】
【题目描述】
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继续回答上面的问题。
Input
第一行有两个正整数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
m,n≤10000
Output
对于每一次询问,你都需要输出他的答案,每一个输出占单独的一行。
Sample Input
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
Sample Output
3
6
6
HINT
Source
【题解】 树状数组套权值线段树模板题。
树状数组每一个节点下开一棵权值线段树,维护这个点所代表的区间。
查询时,把树状数组上需要的节点全部提取出来,一起二分。
修改时,把包含这个点的权值线段树都一起修改。
复杂度 O(n log^2 n)
/* -------------- user Vanisher problem bzoj-1901 ----------------*/ # include <bits/stdc++.h> # define ll long long # define N 10010 # define M 5000000 # define L 0 # define R 1e9 using namespace std; int read(){ int tmp=0, fh=1; char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();} while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();} return tmp*fh; } struct node{ int num,pl,pr; }T[M]; int h[N],a[N],place,incnum,inc[N],decnum,det[N],n,m; int lowbit(int x){ return x&(-x); } void extend(int p, int x, int l, int r){ T[p].num++; if (l!=r){ int mid=(l+r)/2; if (x<=mid){ if (T[p].pl==0) T[p].pl=++place; extend(T[p].pl,x,l,mid); } else { if (T[p].pr==0) T[p].pr=++place; extend(T[p].pr,x,mid+1,r); } } } void del(int p, int x, int l, int r){ T[p].num--; if (l!=r){ int mid=(l+r)/2; if (x<=mid) del(T[p].pl,x,l,mid); else del(T[p].pr,x,mid+1,r); } } int build(int l, int r){ int p=++place; for (int i=l; i<=r; i++) extend(p,a[i],L,R); return p; } void getinc(int x){ incnum=0; while (x>0){ inc[++incnum]=h[x]; x=x-lowbit(x); } } void getdec(int x){ decnum=0; while (x>0){ det[++decnum]=h[x]; x=x-lowbit(x); } } void modify(int p, int x, int k){ del(p,a[x],L,R); extend(p,k,L,R); } int query(int num, int l, int r){ if (l==r) return l; int mid=(l+r)/2,now=0; for (int i=1; i<=incnum; i++) now=now+T[T[inc[i]].pl].num; for (int i=1; i<=decnum; i++) now=now-T[T[det[i]].pl].num; if (now>=num){ for (int i=1; i<=incnum; i++) inc[i]=T[inc[i]].pl; for (int i=1; i<=decnum; i++) det[i]=T[det[i]].pl; return query(num,l,mid); } else { for (int i=1; i<=incnum; i++) inc[i]=T[inc[i]].pr; for (int i=1; i<=decnum; i++) det[i]=T[det[i]].pr; return query(num-now,mid+1,r); } } int main(){ n=read(), m=read(); int l,r,k; for (int i=1; i<=n; i++) a[i]=read(); for (int i=1; i<=n; i++){ l=i-lowbit(i)+1, r=i; h[i]=build(l,r); } char opt; for (int i=1; i<=m; i++){ scanf("\n%c",&opt); if (opt=='Q'){ l=read(), r=read(); k=read(); getinc(r); getdec(l-1); printf("%d\n",query(k,L,R)); } else { l=read(), k=read(); r=l; while (r<=n){ modify(h[r],l,k); r=r+lowbit(r); } a[l]=k; } } return 0; }