AVL平衡树(山东省选 郁闷的小J)

题目描述:

小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


这道题思维难度不大,很容易就可以想出平衡树的正解,难在实现。但其实,将平衡树的模板稍微修改即可过

题解:

这里给出两个思路,一种是对于每种书都做一个平衡树,按那个书的位置排序

第二种是按书的编号排序,编号相同用位置排序,这里采用的是第二种思路

这里是用了结构体重定义运算符来实现的,代码和模板简直一模一样。。。

code:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
  
typedef long long LL;
const int MAXN=200005;
using namespace std;
struct Temp{
    int data,pos;
    Temp(){}
    Temp(int a,int b){
        data=a,pos=b;
    }
    bool operator ==(const Temp &b)const{
        return data==b.data&&pos==b.pos;
    }
    bool operator<(const Temp &b)const{
        if(data==b.data) return pos<b.pos;
        else return data<b.data;
    }
    bool operator>(const Temp &b)const{
        if(data==b.data) return pos>b.pos;
        else return data>b.data;
    }
    bool operator<=(const Temp &b)const{
        return !(*this>b);
    }
    bool operator>=(const Temp &b)const{
        return !(*this<b);
    }
};
struct node{
    int lc,rc,h,num;
    Temp data;
}tree[MAXN+5];
int cnt,root,arr[MAXN],N,M;
  
  
inline void Read(int &Ret){
    char ch;bool flag=0;
    for(;ch=getchar(),ch<'0'||ch>'9';)if(ch=='-')flag=1;
    for(Ret=ch-'0';ch=getchar(),'0'<=ch&&ch<='9';Ret=Ret*10+ch-'0');
    flag&&(Ret=-Ret);
}
inline void update(int i){
    tree[i].h=max(tree[tree[i].lc].h,tree[tree[i].rc].h)+1;
    tree[i].num=tree[tree[i].lc].num+tree[tree[i].rc].num+1;
}
int zig(int i){
    int t=tree[i].lc;
    tree[i].lc=tree[t].rc;
    tree[t].rc=i;
    update(i); update(t);
    return t;
}
int zag(int i){
    int t=tree[i].rc;
    tree[i].rc=tree[t].lc;
    tree[t].lc=i;
    update(i); update(t);
    return t;
}
int zigzag(int i){
    tree[i].rc=zig(tree[i].rc);
    return zag(i);
}
int zagzig(int i){
    tree[i].lc=zag(tree[i].lc);
    return zig(i);
}
   
void maintain(int &i){
    if(tree[tree[i].lc].h==tree[tree[i].rc].h+2)
    {
        int t=tree[i].lc;
        if(tree[tree[t].rc].h==tree[tree[i].rc].h+1) i=zagzig(i);
        else if(tree[tree[t].lc].h==tree[tree[i].rc].h+1) i=zig(i);
    }
    else if(tree[tree[i].rc].h==tree[tree[i].lc].h+2)
    {
        int t=tree[i].rc;
        if(tree[tree[t].lc].h==tree[tree[i].lc].h+1) i=zigzag(i);
        else if(tree[tree[t].rc].h==tree[tree[i].lc].h+1) i=zag(i);
    }
    update(i);
}
void Insert(int &i,Temp x){
    if(!i)
    {
        tree[++cnt].data=x;
        tree[cnt].h=tree[cnt].num=1;
        i=cnt; return;
    }
    if(x<=tree[i].data) Insert(tree[i].lc,x);
    else Insert(tree[i].rc,x);
    maintain(i); return;
}
Temp Delete(int &i,Temp x){
    Temp res;
    if(tree[i].data==x||(x>tree[i].data&&!tree[i].rc)||(x<tree[i].data&&!tree[i].lc))
    {
        res=tree[i].data;
        if(!tree[i].rc||!tree[i].lc)
            {i=tree[i].rc+tree[i].lc;return res;}
        else tree[i].data=Delete(tree[i].lc,x);
    }
    else
    {
        if(x<tree[i].data) res=Delete(tree[i].lc,x);
        else res=Delete(tree[i].rc,x);
    }
    maintain(i); return res;
}
int getrank(int i,Temp x){
    if(!i) return 0;
    if(x<=tree[i].data) return getrank(tree[i].lc,x);
    else  return tree[tree[i].lc].num+1+getrank(tree[i].rc,x);
}
int Query(int a,int b,int num){
    int x=getrank(root,Temp(num,b));
    int y=getrank(root,Temp(num,a));
    if(arr[b]==num) x++; return x-y;
}
int main()
{
    Read(N); Read(M);
    for(int i=1;i<=N;i++)
    {
        scanf("%d",&arr[i]);
        Insert(root,Temp(arr[i],i));
    }
    int a,b,k,p; char ord[5];
    for(int i=1;i<=M;i++)
    {
        scanf("%s",ord);
        switch(ord[0])
        {
            case 'C':
                scanf("%d%d",&a,&p);
                Delete(root,Temp(arr[a],a));
                Insert(root,Temp(p,a));arr[a]=p;
            break;
  
            case 'Q':
                scanf("%d%d%d",&a,&b,&k);
                printf("%d\n",Query(a,b,k));
                break;
        }
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值