• 【山东省选2008】郁闷的小J 平衡树Treap


    小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的书共多少本。

    输出

    对每一个顾客的查询,输出一个整数,表示顾客所要查询的结果。

    样例输入

    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

    提示

    对于40%的数据,1<=N,M<=5000

    对于100%的数据,1<=N,M<=100000

    对于100%的数据,所有出现的书的编码为不大于2147483647的正数。
     
     
    题解:
    本弱用的平衡树Treap做法,开始想的维护一个书的编号和所在书柜的平衡树,然后查找时,先在平衡树找到该编号书所在区域,然后爆搜判断是否满足l<=id<=r,ans++。
    但发现如果平衡树中相同的编号的书太多就会卡成O(n^2),只拿了82分;
    以下是暴力代码:
      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<cstdlib>
      6 #include<ctime>
      7 using namespace std;
      8 const int N=100005;
      9 struct node
     10 {
     11     int x,lev,id;
     12     node *child[2];
     13 }a[N*2];
     14 node *pos,*root;
     15 void newnode(node *&r,int key,int ids)
     16 {
     17     r=pos++;
     18     r->child[0]=r->child[1]=NULL;
     19     r->x=key;
     20     r->id=ids;
     21     r->lev=rand();
     22 }
     23    
     24 int n;
     25 int gi()
     26 {
     27     int str=0;char ch=getchar();
     28     while(ch>'9' || ch<'0')ch=getchar();
     29     while(ch>='0' && ch<='9')str=str*10+ch-'0',ch=getchar();
     30     return str;
     31 }
     32 int b[N];
     33    
     34 void rotate(node *&r,bool t)//0左旋 1右旋
     35 {
     36     node *y=r->child[!t];
     37     r->child[!t]=y->child[t];
     38     y->child[t]=r;
     39     r=y;
     40 }
     41 void insert(node *&r,int key,int ids)
     42 {
     43     if(r==NULL){newnode(r,key,ids);return ;}
     44     bool t=key>r->x;
     45     insert(r->child[t],key,ids);
     46     if(r->child[t]->lev<r->lev)rotate(r,!t);
     47 }
     48    
     49 void Delet(node *&r,int key,int ids)
     50 {
     51     if(r==NULL)return ;
     52     if(r->x==key && r->id==ids)
     53     {
     54         if(r->child[0] && r->child[1])
     55         {
     56             bool t=r->child[0]->lev<r->child[1]->lev;
     57             rotate(r,t);
     58             Delet(r->child[t],key,ids);
     59          }
     60          else
     61          {
     62              if(r->child[0])r=r->child[0];
     63              else r=r->child[1];
     64          }
     65      }
     66     else
     67     {
     68         if(r->x!=key)Delet(r->child[key>r->x],key,ids);
     69         else {
     70                 if(r->child[1])Delet(r->child[1],key,ids);
     71                 if(r->child[0])Delet(r->child[0],key,ids);
     72         }
     73     }
     74 }
     75   
     76 int find(node *&r,int ls,int rs,int key)
     77 {
     78     if(r==NULL)return 0;
     79     int sum=0;
     80     if(r->x==key && r->id>=ls && r->id<=rs)sum++;
     81     if(r->x!=key)sum+=find(r->child[r->x<key],ls,rs,key);//先找到相同编号的书所在区域 
     82     else {//然后爆搜 
     83            if(r->child[0])sum+=find(r->child[0],ls,rs,key);
     84            if(r->child[1])sum+=find(r->child[1],ls,rs,key);
     85     }
     86     return sum;
     87 }
     88  
     89 void check(node *r)//检查的时候用 
     90 {
     91     if(r==NULL)return ;
     92     printf("key=%d id=%d ",r->x,r->id);
     93     if(r->child[1])printf("right=%d ",r->child[1]->x);
     94     if(r->child[0])printf("left=%d ",r->child[0]->x);
     95     printf("
    ");
     96     check(r->child[0]);check(r->child[1]);
     97 }
     98 int main()
     99 {
    100     int m;
    101     n=gi();m=gi();
    102     pos=a;
    103     for(int i=1;i<=n;i++)
    104     {
    105         b[i]=gi();
    106         insert(root,b[i],i);
    107     }
    108     char f;int x,y,z;
    109     while(m--)
    110     {
    111         f=getchar();
    112         while(f!='Q' && f!='C')f=getchar();
    113         if(f=='C')//修改时先删再添加。 
    114         {
    115             x=gi();y=gi();
    116             Delet(root,b[x],x);
    117             b[x]=y;
    118             insert(root,y,x);
    119         }
    120         else if(f=='Q')
    121         {
    122             x=gi();y=gi();z=gi();
    123             printf("%d
    ",find(root,x,y,z));
    124         }
    125     }
    126     return 0;
    127 }

    然后是正解:离散化+Treap

    设询问中C出现的次数为K,只需维护(K+N)个平衡树,用一个*root[N+K]来保存根节点即可实现。

    注意是每一种书对应一颗平衡树,平衡树里保存的是在原数组出现的位置(即书柜号)。

    然后Q L R X的话,先找到X对应的平衡树,再寻找编号在L和R之间的节点个数即可(可以用小于等于R的个数-小于L的个数)。

    C X Y 设读入的数组为a[N],先在a[x]对应的树中删除编号为x的节点,再在Y对应的树中加入编号为X的节点。

    代码如下:

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<cstdlib>
      6 #include<ctime>
      7 using namespace std;
      8 const int N=100005;
      9 struct node
     10 {
     11     int x,lev,size;
     12     node *child[2];
     13 }a[N*2];
     14 struct Ques
     15 {
     16     int flag,x,y,z;
     17 }q[N];
     18 int qm=0;
     19 node *pos,*root[N];
     20 int s[N*2];
     21 void newnode(node *&r,int key)
     22 {
     23     r=pos++;
     24     r->child[0]=r->child[1]=NULL;
     25     r->x=key;
     26     r->size=1;
     27     r->lev=rand();
     28 }
     29 void updata(node *&r)
     30 {
     31     if(r)
     32     r->size=(r->child[0]?r->child[0]->size:0)+(r->child[1]?r->child[1]->size:0)+1;
     33 } 
     34 int n;
     35 int gi()
     36 {
     37     int str=0;char ch=getchar();
     38     while(ch>'9' || ch<'0')ch=getchar();
     39     while(ch>='0' && ch<='9')str=str*10+ch-'0',ch=getchar();
     40     return str;
     41 }
     42 int b[N];
     43    
     44 void rotate(node *&r,bool t)//0左旋 1右旋
     45 {
     46     node *y=r->child[!t];
     47     r->child[!t]=y->child[t];
     48     y->child[t]=r;
     49     updata(r);
     50     r=y;
     51     updata(r);
     52 }
     53 void insert(node *&r,int key)
     54 {
     55     if(r==NULL){newnode(r,key);return ;}
     56     bool t=key>r->x;
     57     insert(r->child[t],key);
     58     if(r->child[t]->lev<r->lev)rotate(r,!t);
     59     updata(r);
     60 }
     61    
     62 void Delet(node *&r,int key)
     63 {
     64     if(r==NULL)return ;
     65     if(r->x==key)
     66     {
     67         if(r->child[0] && r->child[1])
     68         {
     69             bool t=r->child[0]->lev<r->child[1]->lev;
     70             rotate(r,t);
     71             Delet(r->child[t],key);
     72          }
     73          else
     74          {
     75              if(r->child[0])r=r->child[0];
     76              else r=r->child[1];
     77          }
     78      }
     79     else Delet(r->child[key>r->x],key);
     80     updata(r);
     81 }
     82   
     83 int find(node *&r,int key)
     84 {
     85     if(r==NULL)return 0;
     86     int sum=0;
     87     if(r->x<=key){
     88         if(r->child[0])sum+=r->child[0]->size;
     89         sum++;
     90     }
     91     sum+=find(r->child[key>=r->x],key);
     92     return sum;
     93 }
     94  
     95 int py[N*2],bel[N];
     96 int ny=0;
     97 int midit(int x)//二分离散化以后该书对应的新编号 
     98 {
     99     int mid,l=1,r=ny,ans;
    100     while(l<=r)
    101     {
    102         mid=(l+r)>>1;
    103         if(py[mid]<=x)ans=mid,l=mid+1;
    104         else r=mid-1;
    105     }
    106     return ans;
    107 }
    108  
    109 void check(node *r)//检查时用的,可以忽略 
    110 {
    111     if(r==NULL)return ;
    112     printf("key=%d size=%d ",r->x,r->size);
    113     if(r->child[1])printf("right=%d ",r->child[1]->x);
    114     if(r->child[0])printf("left=%d ",r->child[0]->x);
    115     printf("
    ");
    116     check(r->child[0]);check(r->child[1]);
    117 }
    118  
    119 int main()
    120 {
    121     int m;
    122     n=gi();m=gi();
    123     pos=a;
    124     for(int i=1;i<=n;i++)s[i]=b[i]=gi();
    125     char f;int num=n;
    126     for(int i=1;i<=m;i++)//现将数据全部读入,再编号 离散化。 
    127     {
    128         f=getchar();
    129         while(f!='Q' && f!='C')f=getchar();
    130         if(f=='C')
    131         {
    132             q[i].x=gi();q[i].y=gi();
    133             s[++num]=q[i].y;
    134         }
    135         if(f=='Q')
    136         {
    137             q[i].x=gi();q[i].y=gi();q[i].z=gi();
    138             q[i].flag=1;
    139         }
    140     }
    141     sort(s+1,s+num+1); //从小到大排序,方便编号 
    142     for(int i=1;i<=num;i++)if(s[i]!=s[i+1])py[++ny]=s[i];//去重 该操作之后原数组对应的新编号就是py数组的下标。 
    143     int tmp;
    144     for(int i=1;i<=n;i++){
    145         tmp=midit(b[i]);
    146         bel[i]=tmp;//Bel为在书柜i位置的书对应的平衡树root[]中的下标。 
    147         insert(root[tmp],i);
    148     }
    149     for(int i=1;i<=m;i++)
    150     {
    151         if(!q[i].flag)
    152         {
    153             tmp=midit(q[i].y);
    154             Delet(root[bel[q[i].x]],q[i].x);
    155             bel[q[i].x]=tmp;
    156             insert(root[tmp],q[i].x);
    157         }
    158         else
    159         {
    160             tmp=midit(q[i].z);
    161             printf("%d
    ",find(root[tmp],q[i].y)-find(root[tmp],q[i].x-1));
    162         }
    163     }
    164     return 0;
    165 }
  • 相关阅读:
    创建型设计模式之-单例
    设计模式(1、创造型2、结构型、3行为型)
    手写IOC容器和两种注入(构造方法注入和属性注入)
    从依赖倒置原则到IOC控制反转
    自定义HttpHandler可以做什么
    一个用户在浏览器上输入网址怎么走到我们写的.net程序中的,请求到管道处理
    代理Nginx
    .Net Expression表达式目录树(自己动态创建表达式目录树)
    canvas绘制圆环进度条
    城市二级联动
  • 原文地址:https://www.cnblogs.com/Yuzao/p/6756388.html
Copyright © 2020-2023  润新知