问题 A(1846): 【山东省选】郁闷的小J
时间限制: 4 Sec 内存限制: 512 MB题目描述
小J是国家图书馆的一位图书管理员,他的工作是管理一个巨大的书架。虽然他很能吃苦耐劳,但是由于这个书架十分巨大,所以他的工作效率总是很低,以致他面临着被解雇的危险,这也正是他所郁闷的。
具体说来,书架由N个书位组成,编号从1到N。每个书位放着一本书,每本书有一个特定的编码。
小J的工作有两类:
- 图书馆经常购置新书,而书架任意时刻都是满的,所以只得将某位置的书拿掉并换成新购的书。
- 小J需要回答顾客的查询,顾客会询问某一段连续的书位中某一特定编码的书有多少本。
例如,共5个书位,开始时书位上的书编码为1,2,3,4,5
一位顾客询问书位1到书位3中编码为“2”的书共多少本,得到的回答为:1
一位顾客询问书位1到书位3中编码为“1”的书共多少本,得到的回答为:1
此时,图书馆购进一本编码为“1”的书,并将它放到2号书位。
一位顾客询问书位1到书位3中编码为“2”的书共多少本,得到的回答为:0
一位顾客询问书位1到书位3中编码为“1”的书共多少本,得到的回答为:2
……
你的任务是写一个程序来回答每个顾客的询问。
输入
第一行两个整数N,M,表示一共N个书位,M个操作。
接下来一行共N个整数数A1,A2…AN,Ai表示开始时位置i上的书的编码。
接下来M行,每行表示一次操作,每行开头一个字符
若字符为‘C’,表示图书馆购进新书,后接两个整数A(1<=A<=N),P,表示这本书被放在位置A上,以及这本书的编码为P。
若字符为‘Q’,表示一个顾客的查询,后接三个整数A,B,K(1<=A<=B<=N),表示查询从第A书位到第B书位(包含A和B)中编码为K的书共多少本。
(1<=N,M<=100000,所有出现的书的编码为不大于2147483647的正数。)
输出
对每一个顾客的查询,输出一个整数,表示顾客所要查询的结果。
样例输入
5 5
1 2 3 4 5
Q 1 3 2
Q 1 3 1
C 2 1
Q 1 3 2
Q 1 3 1
样例输出
1
1
0
2
朴素地强行直接按照位置来做平衡树是会超时的(后面会给出我的超时代码,可以先拿去交交看)
这里给出两种做法(正解):
法一:
将询问全部读入,离散化书的编号,
然后按照每书的种类不同,每种书建一棵树,树的内容为此种书摆放的位置。
每次C操作先删去原来位置上那种书的树中节点(数组持续更新记录位置上是哪种书),再在新书的树中加入节点
每次Q操作在书的树中累计区间数。
法二:
定义平衡树的顺序为:
1,书的编号种类。2,书的位置(这个注意看结构体里面的重载就比较清晰了)
按正常建树,
每次C操作把原来那个点删除后插入新点
每次Q操作就像查询排名一样后面的排名-前面的排名(注意是在之前的大小定义下)
想不通就想想这棵树的中序遍历,同一类书在中序里是挨在一起的说。
给出两种代码:
Code:
法一:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int Max = 100005;
const int INF = 0x3f3f3f3f;
struct Pro{
int l, r, p;
}Ask[Max];
struct node{
int num, sum;
int lc, rc, h;
}Tr[Max << 1];
int cnt, Pre, Suc;
int Root[Max], B[Max], S[Max << 1], Shelf[Max];
void getint(int & num){
char c; int flg = 1; num = 0;
while((c = getchar()) < '0' || c > '9') if(c == '-') flg = -1;
while(c >= '0' && c <= '9') { num = num * 10 + c - 48; c = getchar();}
num *= flg;
}
int max(int a, int b){ return a < b ? b : a;}
int min(int a, int b){ return a < b ? a : b;}
void pushup(int & r){
Tr[r].sum = Tr[Tr[r].lc].sum + Tr[Tr[r].rc].sum + 1;
Tr[r].h = max(Tr[Tr[r].lc].h, Tr[Tr[r].rc].h) + 1;
}
int zig(int r){
int t = Tr[r].lc;
Tr[r].lc = Tr[t].rc, Tr[t].rc = r;
pushup(r), pushup(t);
return t;
}
int zag(int r){
int t = Tr[r].rc;
Tr[r].rc = Tr[t].lc, Tr[t].lc = r;
pushup(r), pushup(t);
return t;
}
int zigzag(int r){
Tr[r].rc = zig(Tr[r].rc);
return zag(r);
}
int zagzig(int r){
Tr[r].lc = zag(Tr[r].lc);
return zig(r);
}
void maintain(int & r){
if(Tr[Tr[r].lc].h == Tr[Tr[r].rc].h + 2){
int t = Tr[r].lc;
if(Tr[Tr[t].lc].h == Tr[Tr[r].rc].h + 1) r = zig(r);
else if(Tr[Tr[t].rc].h == Tr[Tr[r].rc].h + 1) r = zagzig(r);
}
else if(Tr[Tr[r].rc].h == Tr[Tr[r].lc].h + 2){
int t = Tr[r].rc;
if(Tr[Tr[t].rc].h == Tr[Tr[r].lc].h + 1) r = zag(r);
else if(Tr[Tr[t].lc].h == Tr[Tr[r].lc].h + 1) r = zigzag(r);
}
pushup(r);
}
void Insert(int & r, int val){
if(! r){
r = ++ cnt;
Tr[r].num = val;
Tr[r].h = Tr[r].sum = 1;
return ;
}
if(val < Tr[r].num) Insert(Tr[r].lc, val);
else Insert(Tr[r].rc, val);
maintain(r);
}
int Dele(int & r, int val){
int tx;
if(Tr[r].num == val || (val < Tr[r].num && ! Tr[r].lc) || ( val > Tr[r].num && ! Tr[r].rc)){
if(! Tr[r].lc || ! Tr[r].rc){
tx = Tr[r].num;
r = Tr[r].lc + Tr[r].rc;
return tx;
}
else Tr[r].num = Dele(Tr[r].lc, val);
}
else {
if(val < Tr[r].num) tx = Dele(Tr[r].lc, val);
else tx = Dele(Tr[r].rc, val);
}
maintain(r);
return tx;
}
int Search(int &r, int pos){
if(! r) return 0;
int sum = 0;
if(Tr[r].num <= pos){
if(Tr[r].lc) sum += Tr[Tr[r].lc].sum;
++ sum;
}
if(Tr[r].num <= pos) sum += Search(Tr[r].rc, pos);
else sum += Search(Tr[r].lc, pos);
return sum;
}
int main(){
int N, M, tot;
getint(N), getint(M);
for(int i = 1; i <= N; ++ i){
getint(B[i]);
S[i] = B[i];
}
char ord[5];
tot = N;
for(int i = 1; i <= M; ++ i){
scanf("%s", ord);
if(ord[0] == 'Q'){
getint(Ask[i].l), getint(Ask[i].r);
getint(Ask[i].p);
S[++ tot] = Ask[i].p;
}
else {
getint(Ask[i].l), getint(Ask[i].p);
Ask[i].r = -1;
}
}
sort(S + 1, S + tot + 1);
int len = unique(S + 1, S + tot + 1) - S;
int tmp;
for(int i = 1; i <= N; ++ i){
tmp = lower_bound(S + 1, S + 1 + len, B[i]) - S;
Shelf[i] = tmp;
Insert(Root[tmp], i);
}
for(int i = 1; i <= M; ++ i){
if(Ask[i].r != -1){
tmp = lower_bound(S + 1, S + 1 + len, Ask[i].p) - S;
printf("%d\n", Search(Root[tmp], Ask[i].r) - Search(Root[tmp], Ask[i].l - 1));
}
else {
tmp = lower_bound(S + 1, S + 1 + len, Ask[i].p) - S;
Dele(Root[Shelf[Ask[i].l]], Ask[i].l);
Shelf[Ask[i].l] = tmp;
Insert(Root[tmp], Ask[i].l);
}
}
return 0;
}
法二:
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int Max = 100005;
const int INF = 0x3f3f3f3f;
struct bk{
int biao, pos;
bk(){}
bk(int a, int b){biao = a, pos = b;}
bool operator <(const bk & X)const{
if(biao == X.biao) return pos < X.pos;
return biao < X.biao;
}
bool operator == (const bk & X)const{
return biao == X.biao && pos == X.pos;
}
};
struct node{
bk num;
int lc, rc, h, sum;
}Tr[Max << 1];
int cnt;
int Shelf[Max];
void getint(int & num){
char c; int flg = 1; num = 0;
while((c = getchar()) < '0' || c > '9') if(c == '-') flg = -1;
while(c >= '0' && c <= '9') { num = num * 10 + c - 48; c = getchar();}
num *= flg;
}
int max(int a, int b){ return a < b ? b : a;}
int min(int a, int b){ return a < b ? a : b;}
void pushup(int & r){
Tr[r].h = max(Tr[Tr[r].lc].h, Tr[Tr[r].rc].h) + 1;
Tr[r].sum = Tr[Tr[r].lc].sum + Tr[Tr[r].rc].sum + 1;
}
int zig(int r){
int t = Tr[r].lc;
Tr[r].lc = Tr[t].rc, Tr[t].rc = r;
pushup(r), pushup(t);
return t;
}
int zag(int r){
int t = Tr[r].rc;
Tr[r].rc = Tr[t].lc, Tr[t].lc = r;
pushup(r), pushup(t);
return t;
}
int zigzag(int r){
Tr[r].rc = zig(Tr[r].rc);
return zag(r);
}
int zagzig(int r){
Tr[r].lc = zag(Tr[r].lc);
return zig(r);
}
void maintain(int & r){
if(Tr[Tr[r].lc].h == Tr[Tr[r].rc].h + 2){
int t = Tr[r].lc;
if(Tr[Tr[t].lc].h == Tr[Tr[r].rc].h + 1) r = zig(r);
else if(Tr[Tr[t].rc].h == Tr[Tr[r].rc].h + 1) r = zagzig(r);
}
else if(Tr[Tr[r].rc].h == Tr[Tr[r].lc].h + 2){
int t = Tr[r].rc;
if(Tr[Tr[t].rc].h == Tr[Tr[r].lc].h + 1) r = zag(r);
else if(Tr[Tr[t].lc].h == Tr[Tr[r].lc].h + 1) r = zigzag(r);
}
pushup(r);
}
void Insert(int & r, bk val){
if(! r){
r = ++ cnt;
Tr[r].num = val;
Tr[r].h = Tr[r].sum = 1;
return ;
}
if(val < Tr[r].num) Insert(Tr[r].lc, val);
else Insert(Tr[r].rc, val);
maintain(r);
}
bk Dele(int & r, bk val){
bk tx;
if(Tr[r].num == val || (val < Tr[r].num && ! Tr[r].lc) || (Tr[r].num < val && ! Tr[r].rc)){
if(! Tr[r].lc || ! Tr[r].rc){
tx = Tr[r].num;
r = Tr[r].lc + Tr[r].rc;
return tx;
}
else Tr[r].num = Dele(Tr[r].lc, val);
}
else {
if(val < Tr[r].num) tx = Dele(Tr[r].lc, val);
else tx = Dele(Tr[r].rc, val);
}
maintain(r);
return tx;
}
int Query(int r, bk val){
if(! r) return 0;
if(Tr[r].num < val) return Tr[Tr[r].lc].sum + 1 + Query(Tr[r].rc, val);
return Query(Tr[r].lc, val);
}
int main(){
int R = 0, N, M, A, B, K;
getint(N), getint(M);
for(int i = 1; i <= N; ++ i){
getint(Shelf[i]);
Insert(R, bk(Shelf[i], i));
}
char ord[10];
while(M --){
scanf("%s", ord);
switch(ord[0]){
case 'Q':{
getint(A), getint(B), getint(K);
printf("%d\n", Query(R, bk(K, B)) - Query(R, bk(K, A)) + (Shelf[B] == K));
break;
}
case 'C':{
getint(A), getint(K);
Dele(R, bk(Shelf[A], A));
Shelf[A] = K;
Insert(R, bk(K, A));
break;
}
}
}
return 0;
}
超时的朴素代码。。。。如下(留做个纪念吧,还是打了一小会儿呢):
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int Max = 200005;
const int INF = 0x3f3f3f3f;
struct bk{
int biao, pos;
bk(){}
bk(int a, int b){biao = a, pos = b;}
};
struct node{
bk num;
int lc, rc, h;
}Tr[Max];
int cnt, Pre, Suc;
void getint(int & num){
char c; int flg = 1; num = 0;
while((c = getchar()) < '0' || c > '9') if(c == '-') flg = -1;
while(c >= '0' && c <= '9') { num = num * 10 + c - 48; c = getchar();}
num *= flg;
}
int max(int a, int b){ return a < b ? b : a;}
int min(int a, int b){ return a < b ? a : b;}
void pushup(int & r){
Tr[r].h = max(Tr[Tr[r].lc].h, Tr[Tr[r].rc].h) + 1;
}
int zig(int r){
int t = Tr[r].lc;
Tr[r].lc = Tr[t].rc, Tr[t].rc = r;
pushup(r), pushup(t);
return t;
}
int zag(int r){
int t = Tr[r].rc;
Tr[r].rc = Tr[t].lc, Tr[t].lc = r;
pushup(r), pushup(t);
return t;
}
int zigzag(int r){
Tr[r].rc = zig(Tr[r].rc);
return zag(r);
}
int zagzig(int r){
Tr[r].lc = zag(Tr[r].lc);
return zig(r);
}
void maintain(int & r){
if(Tr[Tr[r].lc].h == Tr[Tr[r].rc].h + 2){
int t = Tr[r].lc;
if(Tr[Tr[t].lc].h == Tr[Tr[r].rc].h + 1) r = zig(r);
else if(Tr[Tr[t].rc].h == Tr[Tr[r].rc].h + 1) r = zagzig(r);
}
else if(Tr[Tr[r].rc].h == Tr[Tr[r].lc].h + 2){
int t = Tr[r].rc;
if(Tr[Tr[t].rc].h == Tr[Tr[r].lc].h + 1) r = zag(r);
else if(Tr[Tr[t].lc].h == Tr[Tr[r].lc].h + 1) r = zigzag(r);
}
pushup(r);
}
void Insert(int & r, bk val){
if(! r){
r = ++ cnt;
Tr[r].num = val;
Tr[r].h = 1;
return ;
}
if(val.pos < Tr[r].num.pos) Insert(Tr[r].lc, val);
else Insert(Tr[r].rc, val);
maintain(r);
}
bk Dele(int & r, int pos){
bk tx;
if(Tr[r].num.pos == pos || (pos < Tr[r].num.pos && ! Tr[r].lc) || (pos > Tr[r].num.pos && ! Tr[r].rc)){
if(! Tr[r].lc || ! Tr[r].rc){
tx = Tr[r].num;
r = Tr[r].lc + Tr[r].rc;
return tx;
}
else Tr[r].num = Dele(Tr[r].lc, pos);
}
else {
if(pos < Tr[r].num.pos) tx = Dele(Tr[r].lc, pos);
else tx = Dele(Tr[r].rc, pos);
}
maintain(r);
return tx;
}
int Query(int R, int l, int r, int k){
if(! R) return 0;
if(Tr[R].num.pos < l) return Query(Tr[R].rc, l, r, k);
if(Tr[R].num.pos > r) return Query(Tr[R].lc, l, r, k);
bool flg = 0;
if(Tr[R].num.biao == k) flg = 1;
return flg + Query(Tr[R].lc, l, r, k) + Query(Tr[R].rc, l, r, k);
}
int main(){
int R = 0, N, M, x, A, B, K;
getint(N), getint(M);
for(int i = 1; i <= N; ++ i){
getint(x);
Insert(R, bk(x, i));
}
char ord[10];
while(M --){
scanf("%s", ord);
switch(ord[0]){
case 'Q':{
getint(A), getint(B), getint(K);
printf("%d\n", Query(R, A, B, K));
break;
}
case 'C':{
getint(A), getint(K);
Dele(R, A);
Insert(R, bk(K, A));
break;
}
}
}
return 0;
}