Link:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1112
The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query like to simply find the k-th smallest number of the given N numbers. They have developed a more powerful system such that for N numbers a[1], a[2], ..., a[N], you can ask it like: what is the k-th smallest number of a[i], a[i+1], ..., a[j]? (For some i<=j, 0<k<=j+1-i that you have given to it). More powerful, you can even change the value of some a[i], and continue to query, all the same.
Your task is to write a program for this computer, which
- Reads N numbers from the input (1 <= N <= 50,000)
- Processes M instructions of the input (1 <= M <= 10,000). These instructions include querying the k-th smallest number of a[i], a[i+1], ..., a[j] and change some a[i] to t.
Input
The first line of the input is a single number X (0 < X <= 4), the number of the test cases of the input. Then X blocks each represent a single test case.
The first line of each block contains two integers N and M, representing N numbers and M instruction. It is followed by N lines. The (i+1)-th line represents the number a[i]. Then M lines that is in the following format
Q i j k or
C i t
It represents to query the k-th number of a[i], a[i+1], ..., a[j] and change some a[i] to t, respectively. It is guaranteed that at any time of the operation. Any number a[i] is a non-negative integer that is less than 1,000,000,000.
There're NO breakline between two continuous test cases.
Output
For each querying operation, output one integer to represent the result. (i.e. the k-th smallest number of a[i], a[i+1],..., a[j])
There're NO breakline between two continuous test cases.
Sample Input
2
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
Sample Output
3
6
3
6
(adviser)
Site: http://zhuzeyuan.hp.infoseek.co.jp/index.files/our_contest_20040619.htm
Author: XIN, Tao
Source: Online Contest of Christopher's Adventure
参考博客:http://blog.youkuaiyun.com/d891320478/article/details/8648171
AC code:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define N 60010
#define M 60010
#define INF 1000000000
char ctrl[M][3];
int cnt,n,m;
int P[M],Q[M],a[N],b[N],K[M];
struct treap{
int key,wei,cnt,size,ch[2];
}T[N * 15];
int tree[N << 1],nodecnt,root;
void init(){
T[0].size = 0;
T[0].wei = -INF;
nodecnt = root = 0;
}
int ID(int l,int r){return l + r | l != r;}
void update(int x){
T[x].size = T[T[x].ch[0]].size + T[T[x].ch[1]].size + T[x].cnt;
}
void rotate(int &x,int t){
int y = T[x].ch[t];
T[x].ch[t] = T[y].ch[!t];
T[y].ch[!t] = x;
update(x);
update(y);
x = y;
}
void insert(int &x,int t){
if (!x){
x = ++ nodecnt;
T[x].key = t;
T[x].wei = rand();
T[x].cnt = 1;
T[x].ch[0] = T[x].ch[1] = 0;
}else if (T[x].key == t) T[x].cnt ++;
else{
int k = T[x].key < t;
insert(T[x].ch[k],t);
if (T[x].wei < T[T[x].ch[k]].wei) rotate(x,k);
}
update(x);
}
void erase(int &x,int t){
if (T[x].key == t){
if (T[x].cnt == 1){
if (!T[x].ch[0] && !T[x].ch[1]) {
x = 0;return;
}
rotate(x,T[T[x].ch[0]].wei < T[T[x].ch[1]].wei);
erase(x,t);
}else T[x].cnt --;
}else erase(T[x].ch[T[x].key < t],t);
update(x);
}
int select(int x,int t){
if (!x) return 0;
if (T[x].key > t) return select(T[x].ch[0],t);
return T[x].cnt + T[T[x].ch[0]].size + select(T[x].ch[1],t);
}
void treeins(int l,int r,int i,int x){
insert(tree[ID(l,r)],x);
if (l == r) return;
int m = l + r >> 1;
if (i <= m) treeins(l,m,i,x);
else treeins(m + 1,r,i,x);
}
void treedel(int l,int r,int i,int x){
erase(tree[ID(l,r)],x);
if (l == r) return;
int m = l + r >> 1;
if (i <= m) treedel(l,m,i,x);
else treedel(m + 1,r,i,x);
}
int query(int l,int r,int x,int y,int t){
if (l == r) return l;
int m = l + r >> 1;
int ans = select(tree[ID(l,m)],y) - select(tree[ID(l,m)],x);
if (ans >= t) return query(l,m,x,y,t);
return query(m + 1,r,x,y,t - ans);
}
int main(){
//freopen("in.txt","r",stdin);
int Times;
int cas;
scanf("%d",&cas);
while(cas--){
scanf("%d%d",&n,&m);
memset(tree,0,sizeof tree);
init();
cnt = 0;
for (int i = 1;i <= n;i ++) scanf("%d",&a[i]),b[++ cnt] = a[i];
for (int i = 1;i <= m;i ++){
scanf("%s%d%d",ctrl[i],&P[i],&Q[i]);
if (ctrl[i][0] == 'Q') scanf("%d",&K[i]);
else b[++ cnt] = Q[i];
}
sort(b + 1,b + 1 + cnt);
cnt = unique(b + 1,b + 1 + cnt) - b - 1;
for (int i = 1;i <= n;i ++) {
a[i] = lower_bound(b + 1,b + 1 + cnt,a[i]) - b;
treeins(1,cnt,a[i],i);
}
for (int i = 1;i <= m;i ++){
if (ctrl[i][0] == 'Q'){
int id = query(1,cnt,P[i] - 1,Q[i],K[i]);
printf("%d\n",b[id]);
}else{
treedel(1,cnt,a[P[i]],P[i]);
a[P[i]] = lower_bound(b + 1,b + 1 + cnt,Q[i]) - b;
treeins(1,cnt,a[P[i]],P[i]);
}
}
}
return 0;
}
附上别人较简化的代码版本(通过加二分分治优化):
该代码来自博客:http://blog.youkuaiyun.com/firenet1/article/details/47858071
AC code:
#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));
int cas;
scanf("%d",&cas);
while(cas--){
scanf("%d%d",&n,&q);
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;
char ch;
for(int i = 0;i < q; i++,cnt++){
scanf("\n%ch",&ch);
if(ch=='Q')
{
p[cnt].ty=2;
}
else
{
p[cnt].ty=1;
}
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;
}
两份代码比较,显然第二份(后提交的那份)更优:
Run ID | Submit Time | Judge Status | Pro.ID | Exe.Time | Exe.Memory | Code Len. | Language | Author |
14688861 | 2015-08-29 23:02:59 | Accepted | 5412 | 1918MS | 11248K | 2440 B | G++ | 落纸云烟 |
14688457 | 2015-08-29 21:58:02 | Accepted | 5412 | 4414MS | 83288K | 3251 B | G++ | 落纸云烟 |