Queue-jumpers
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1663 Accepted Submission(s): 393
Problem Description
Ponyo and Garfield are waiting outside the box-office for their favorite movie. Because queuing is so boring, that they want to play a game to kill the time. The game is called “Queue-jumpers”. Suppose that there are N people numbered from 1 to N stand in a line initially. Each time you should simulate one of the following operations:
1. Top x :Take person x to the front of the queue
2. Query x: calculate the current position of person x
3. Rank x: calculate the current person at position x
Where x is in [1, N].
Ponyo is so clever that she plays the game very well while Garfield has no idea. Garfield is now turning to you for help.
1. Top x :Take person x to the front of the queue
2. Query x: calculate the current position of person x
3. Rank x: calculate the current person at position x
Where x is in [1, N].
Ponyo is so clever that she plays the game very well while Garfield has no idea. Garfield is now turning to you for help.
Input
In the first line there is an integer T, indicates the number of test cases.(T<=50)
In each case, the first line contains two integers N(1<=N<=10^8), Q(1<=Q<=10^5). Then there are Q lines, each line contain an operation as said above.
In each case, the first line contains two integers N(1<=N<=10^8), Q(1<=Q<=10^5). Then there are Q lines, each line contain an operation as said above.
Output
For each test case, output “Case d:“ at first line where d is the case number counted from one, then for each “Query x” operation ,output the current position of person x at a line, for each “Rank x” operation, output the current person at position x at a line.
Sample Input
3 9 5 Top 1 Rank 3 Top 7 Rank 6 Rank 8 6 2 Top 4 Top 5 7 4 Top 5 Top 2 Query 1 Rank 6题意:给你1--N的数字,从小到大排列,可以执行操作:TOP x把x放到最前面Rank x 问x数字在第几位Query x wen在x位置上的数字是什么这道题有很多解法:splay等高级数据结构可以写的,但是代码太多。树状数组+离散化比较容易些,但是很难想到我用的是树状数组,但是比较麻烦思路:分两步来做:1.rank,query操作的x被调到队列前面了初始tail = 100000,tail表示队列首位的位置,因为可能top100000次setmap 记录x是否被top过,前当前的tail标号hahamap 记录每个tail值对应的数字每当top x时,如果x已经被top了 ,数组数组setmap[x]的值减一,就把setmap[x]=tail,同时更新hahamap[tail]=x,然后tail--。如果没被top过,就直接更新setmap,hahamap,rank x;如果x的大小<=setmap的大小,说明可以在setmap里找到这个数字,用二分的方法找到y,使得setmap[y]-tail+sum(y)==x就找到了rank 为x的数了, 这个树状数组表示前y个数中有几个值被重复topquery x:如果x被top过setmap[x] - tail + sum(y) 就是他的rank2rank,query的x都不曾被top过用一个map top ,top[x]表示x被top了几次,树状数组清空,top里存被top过的数有几个,且被top过几次用一个vector low对所有的被top的数字从小到大排序,离线逆序解决问题,如果遇到top x,那么top[x]--,如果top[x]=0,表示在这个top操作前,x没被top过,x在low所在的位置,position,在树状数组中position+1位置-1,表示当前位置少了一个数字。为什么是+1位置呢:因为树状数组的add,sum操作,不能获得0位置上的值,rank x:二分查找,对一个数y,top.size() + y - 被top过小于y的数字个数,就是y的rank,如果==x,说明就是y了query x操作:x + top.size() - low中存在的且<x的数字个数就是答案代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<set> #include<algorithm> #include<map> #include<vector> #include<string> #define sec second #define fir first using namespace std; const int maxn = 100009; int N,M; int shu[maxn+1]; int lowbit(int i){ return i&(-i); } int add(int i,int a){ while(i <= maxn){ shu[i] += a; i += lowbit(i); } return 0; } int sum(int i){ int res = 0; while(i > 0){ res += shu[i]; i -= lowbit(i); } return res; } int tail = 0; int res[maxn]; map<int,int> hahamap; map<int,int> setmap; vector<int> low; map<int,int> top; pair<string,int> question[maxn]; int main() { int t,x,position;char a[100]; scanf("%d",&t); for(int tt = 1; tt <= t; tt++){ printf("Case %d:\n",tt); scanf("%d%d",&N,&M); memset(shu,0,sizeof(shu));//树状数组清空 memset(res,-1,sizeof(res));//答案标记 low.clear();//排序数组清空 hahamap.clear();// setmap.clear(); top.clear(); tail = 100000; for(int i = 0;i < M; i++){ scanf("%s %d",a,&x); question[i].fir = (string)a; question[i].sec = x; if(a[0] == 'T'){ hahamap[tail] = x; if(setmap.find(x) == setmap.end()){//没被top过, low.push_back(x);//记录这个被top的值 top[x] = 1; setmap[x] = tail--; } else{ top[x]++; add(setmap[x],-1); setmap[x] = tail--; } } else if(a[0] == 'Q'){ if(setmap.find(x) != setmap.end()){ int ans = setmap[x] - tail + sum(setmap[x]); res[i] = ans; } } else { if(setmap.size() >= x){ int li = tail,high = 100000,mid;//二分rank while(li <= high){ mid = (li+high)/2; int ans = mid - tail + sum(mid);//计算数字为mid的rank if(ans < x) li = mid+1;//rank大于x,说明数字太小 else high = mid - 1; } res[i] = hahamap[li]; } } } sort(low.begin(),low.end());//对被top的数排序 memset(shu,0,sizeof(shu));//清空数组 for(int i = M-1;i >= 0;i--){ if(res[i] != -1) continue; x = question[i].sec; if(question[i].fir[0] == 'T'){ top[x]--;//逆序中,检查x是否top次数为0了 if(top[x] == 0){ top.erase(x); position = lower_bound(low.begin(),low.end(),x) - low.begin(); add(position+1,-1);//在这次top前,top次数为0,表示这个x离开top序列了 } } else if(question[i].fir[0] == 'R'){ int li = x - top.size(), high = x ,mid; while(li <= high){//查找rank 为x的数字, mid = (li+high)/2; position = upper_bound(low.begin(),low.end(),mid) - low.begin(); int ans = top.size() + mid - (position + sum(position));// //因为插入时,将x所在的位置+1了,而upper_bound找第一个大于x的数字 //所以不需要position-1+1的操作了 if(ans < x)li = mid+1; else high = mid-1; } res[i] = li; } else{ position = upper_bound(low.begin(),low.end(),x) - low.begin(); int ans = top.size() + x - (position + sum(position)); res[i] = ans; } } for(int i = 0;i < M; i++){ if(question[i].fir[0] =='T')continue; printf("%d\n",res[i]); } } return 0; } /* 23 10000 18 T 3 T 4 T 7 Q 4 R 2 T 4 Q 4 Q 6 Q 7 Q 8 R 6 R 5 T 3 T 7 Q 4 Q 5 R 4 R 5 */