小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=;
  9. struct node
  10. {
  11. int x,lev,id;
  12. node *child[];
  13. }a[N*];
  14. node *pos,*root;
  15. void newnode(node *&r,int key,int ids)
  16. {
  17. r=pos++;
  18. r->child[]=r->child[]=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=;char ch=getchar();
  28. while(ch>'' || ch<'')ch=getchar();
  29. while(ch>='' && ch<='')str=str*+ch-'',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[] && r->child[])
  55. {
  56. bool t=r->child[]->lev<r->child[]->lev;
  57. rotate(r,t);
  58. Delet(r->child[t],key,ids);
  59. }
  60. else
  61. {
  62. if(r->child[])r=r->child[];
  63. else r=r->child[];
  64. }
  65. }
  66. else
  67. {
  68. if(r->x!=key)Delet(r->child[key>r->x],key,ids);
  69. else {
  70. if(r->child[])Delet(r->child[],key,ids);
  71. if(r->child[])Delet(r->child[],key,ids);
  72. }
  73. }
  74. }
  75.  
  76. int find(node *&r,int ls,int rs,int key)
  77. {
  78. if(r==NULL)return ;
  79. int sum=;
  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[])sum+=find(r->child[],ls,rs,key);
  84. if(r->child[])sum+=find(r->child[],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[])printf("right=%d ",r->child[]->x);
  94. if(r->child[])printf("left=%d ",r->child[]->x);
  95. printf("\n");
  96. check(r->child[]);check(r->child[]);
  97. }
  98. int main()
  99. {
  100. int m;
  101. n=gi();m=gi();
  102. pos=a;
  103. for(int i=;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\n",find(root,x,y,z));
  124. }
  125. }
  126. return ;
  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=;
  9. struct node
  10. {
  11. int x,lev,size;
  12. node *child[];
  13. }a[N*];
  14. struct Ques
  15. {
  16. int flag,x,y,z;
  17. }q[N];
  18. int qm=;
  19. node *pos,*root[N];
  20. int s[N*];
  21. void newnode(node *&r,int key)
  22. {
  23. r=pos++;
  24. r->child[]=r->child[]=NULL;
  25. r->x=key;
  26. r->size=;
  27. r->lev=rand();
  28. }
  29. void updata(node *&r)
  30. {
  31. if(r)
  32. r->size=(r->child[]?r->child[]->size:)+(r->child[]?r->child[]->size:)+;
  33. }
  34. int n;
  35. int gi()
  36. {
  37. int str=;char ch=getchar();
  38. while(ch>'' || ch<'')ch=getchar();
  39. while(ch>='' && ch<='')str=str*+ch-'',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[] && r->child[])
  68. {
  69. bool t=r->child[]->lev<r->child[]->lev;
  70. rotate(r,t);
  71. Delet(r->child[t],key);
  72. }
  73. else
  74. {
  75. if(r->child[])r=r->child[];
  76. else r=r->child[];
  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 ;
  86. int sum=;
  87. if(r->x<=key){
  88. if(r->child[])sum+=r->child[]->size;
  89. sum++;
  90. }
  91. sum+=find(r->child[key>=r->x],key);
  92. return sum;
  93. }
  94.  
  95. int py[N*],bel[N];
  96. int ny=;
  97. int midit(int x)//二分离散化以后该书对应的新编号
  98. {
  99. int mid,l=,r=ny,ans;
  100. while(l<=r)
  101. {
  102. mid=(l+r)>>;
  103. if(py[mid]<=x)ans=mid,l=mid+;
  104. else r=mid-;
  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[])printf("right=%d ",r->child[]->x);
  114. if(r->child[])printf("left=%d ",r->child[]->x);
  115. printf("\n");
  116. check(r->child[]);check(r->child[]);
  117. }
  118.  
  119. int main()
  120. {
  121. int m;
  122. n=gi();m=gi();
  123. pos=a;
  124. for(int i=;i<=n;i++)s[i]=b[i]=gi();
  125. char f;int num=n;
  126. for(int i=;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=;
  139. }
  140. }
  141. sort(s+,s+num+); //从小到大排序,方便编号
  142. for(int i=;i<=num;i++)if(s[i]!=s[i+])py[++ny]=s[i];//去重 该操作之后原数组对应的新编号就是py数组的下标。
  143. int tmp;
  144. for(int i=;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=;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\n",find(root[tmp],q[i].y)-find(root[tmp],q[i].x-));
  162. }
  163. }
  164. return ;
  165. }

【山东省选2008】郁闷的小J 平衡树Treap的更多相关文章

  1. 洛谷P2464 [SDOJ2008]郁闷的小J

    洛谷P2464 [SDOJ2008]郁闷的小J 题目描述 小J是国家图书馆的一位图书管理员,他的工作是管理一个巨大的书架.虽然他很能吃苦耐劳,但是由于这个书架十分巨大,所以他的工作效率总是很低,以致他 ...

  2. [SDOI2008]郁闷的小J(分块)

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

  3. 洛谷P2464 [SDOI2008] 郁闷的小j [分块]

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

  4. 山东省选 郁闷的小J

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

  5. P2464 [SDOI2008]郁闷的小J

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

  6. fhqtreap - Luogu 2464 [SDOI2008]郁闷的小J

    [SDOI2008]郁闷的小JJ 题目描述 小J是国家图书馆的一位图书管理员,他的工作是管理一个巨大的书架.虽然他很能吃苦耐劳,但是由于这个书架十分巨大,所以他的工作效率总是很低,以致他面临着被解雇的 ...

  7. 2018.09.26 洛谷P2464 [SDOI2008]郁闷的小J(map+vector)

    传送门 本来出题人出出来想考数据结构的. 但是我们拥有map+vector/set这样优秀的STL,因此直接用map离散化,vector存下标在里面二分找答案就行了. 代码: #include< ...

  8. 【洛谷 P2464】[SDOI2008]郁闷的小J(线段树)

    题目链接 这题我很久之前用分块写过,没写出来.. 今天又看到了,于是下决心把这题做出来. 这次我用线段树写的,直接对每本书的编号Hash一下然后离散化然后各建一棵线段树,维护当前编号在某个位置有没有书 ...

  9. HUST-1407 郁闷的小J

    离线做法:分别处理每个编号上的各种询问和操作,接着就能用树状数组维护. #include <cstdlib> #include <cstdio> #include <cs ...

随机推荐

  1. 分享小知识:善用Group By排序

    以下列举了公用表/临时表/聚合函数三个因素为例子(覆盖索引因素除外,有利用此类索引都会以索引顺序)  环境: Microsoft SQL Server 2014 (SP1-GDR) (KB319472 ...

  2. jump堡垒机配置使用

    一.用户管理 1)添加用户 点击用户管理 —> 查看用户 —> 添加用户 输入要添加的用户名,姓名,权限,Mail,并且发送邮件 —> 保存 查看添加的用户 查看用户邮件 邮件中包含 ...

  3. Oh, my god令人头痛的“对象”--------C#数据类型

    1.C#常用的数据类型: ①整型            int ②浮点型         float ③双精度型      double ④字符串         string ⑤布尔类型       ...

  4. [原创]ASM动态修改JAVA函数之函数字节码初探

    ASM是非常强大的JAVA字节码生成和修改工具,具有性能优异.文档齐全.比较易用等优点.官方网站:http://asm.ow2.org/ 要想熟练的使用ASM,需要对java字节码有一定的了解,本文重 ...

  5. 使文字在div中水平和垂直居中的的css样式为,四个边分别设置阴影样式

    text-align:center; /*水平居中*/ line-height: 20px; /*行距设为与div高度一致*/ HTML元素 <div>水平垂直居中</div> ...

  6. iOS开发之UICollectionViewController

    1.概述 UICollectionView控件主要是用来做九宫格的,类似于android中的GridView控件.其用法与UITableView一样,首先要使控制器遵守数据源协议,再将控制器设置为UI ...

  7. Memcached十问十答

    1.Memcached是什么,有什么作用? Memcached是一种纯内存的,key-value,CS架构的数据库服务软件,主要用于数据库,web服务器的缓存,以减小数据库,web服务器的访问压力,尤 ...

  8. java做帐户登录失败锁定

    对于连续失败登录应用系统5次的帐号,需锁定该帐号至少30分钟不允许登录. 这里也用简单的map集合进行判定,功能能实现,但并不是很完美,不用更改数据库的表字段 1.首先建立一个用户登陆失败的实体类 p ...

  9. iOS关于友盟分享弹不出面板问题

    在程序代理类中声明 [NSThread sleepForTimeInterval:10];//设置启动页面时间 [self.window makeKeyAndVisible]; [[UMSocialM ...

  10. Weblogic+apache多虚拟主机

    p.MsoNormal,li.MsoNormal,div.MsoNormal { margin: 0cm; margin-bottom: .0001pt; text-align: justify; f ...