#bzoj1846 - 山东省选2008#郁闷的小J(Avl平衡树两法:离散化每种书建树 or 按特定排序建一棵树)

问题 A(1846): 【山东省选】郁闷的小J

时间限制: 4 Sec  内存限制: 512 MB

题目描述

小J是国家图书馆的一位图书管理员,他的工作是管理一个巨大的书架。虽然他很能吃苦耐劳,但是由于这个书架十分巨大,所以他的工作效率总是很低,以致他面临着被解雇的危险,这也正是他所郁闷的。

       具体说来,书架由N个书位组成,编号从1到N。每个书位放着一本书,每本书有一个特定的编码。

       小J的工作有两类:

  1. 图书馆经常购置新书,而书架任意时刻都是满的,所以只得将某位置的书拿掉并换成新购的书。
  2. 小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;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值