KiKi's K-Number
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3847 Accepted Submission(s): 1707
Problem Description
For the k-th number, we all should be very familiar with it. Of course,to kiki it is also simple. Now Kiki meets a very similar problem, kiki wants to design a container, the container is to support the three operations.
Push: Push a given element e to container
Pop: Pop element of a given e from container
Query: Given two elements a and k, query the kth larger number which greater than a in container;
Although Kiki is very intelligent, she can not think of how to do it, can you help her to solve this problem?
Push: Push a given element e to container
Pop: Pop element of a given e from container
Query: Given two elements a and k, query the kth larger number which greater than a in container;
Although Kiki is very intelligent, she can not think of how to do it, can you help her to solve this problem?
Input
Input some groups of test data ,each test data the first number is an integer m (1 <= m <100000), means that the number of operation to do. The next m lines, each line will be an integer p at the beginning, p which has three values:
If p is 0, then there will be an integer e (0 <e <100000), means press element e into Container.
If p is 1, then there will be an integer e (0 <e <100000), indicated that delete the element e from the container
If p is 2, then there will be two integers a and k (0 <a <100000, 0 <k <10000),means the inquiries, the element is greater than a, and the k-th larger number.
If p is 0, then there will be an integer e (0 <e <100000), means press element e into Container.
If p is 1, then there will be an integer e (0 <e <100000), indicated that delete the element e from the container
If p is 2, then there will be two integers a and k (0 <a <100000, 0 <k <10000),means the inquiries, the element is greater than a, and the k-th larger number.
Output
For each deletion, if you want to delete the element which does not exist, the output "No Elment!". For each query, output the suitable answers in line .if the number does not exist, the output "Not Find!".
Sample Input
5 0 5 1 2 0 6 2 3 2 2 8 1 7 0 2 0 2 0 4 2 1 1 2 1 2 2 1 3 2 1 4
Sample Output
No Elment! 6 Not Find! 2 2 4 Not Find!
题意:题目给定三种操作: 0 x 表示把x插入容器 ; 1 x 表示删除一个x如果没有x则输出 No Elment! ; 2 a k 表示比a大的数中的第k大的数 如果没有输出No Find!
思路:网上大神说看到删除元素增加元素就可以想到用树状数组做。。。(做笔记),所以用树状数组写了,其实知道用树桩数组写还蛮好写的,只不过我被卡了一下二分。。求比a大的某个数,就是在后面比a大的数里面找第k个,怎么找呢。。。用sum(x) - sum(now) = k;说明这个区间里有k个元素,如果now = 1的话肯定就是now了,如果now不等于1说明在前面某个点是要求的点。。一般是枚举每个点,sum(i) - sum(x)看哪个点可以让他 = k,用二分优化。。我被卡在,如果这个点有多个值,比如2这个元素有多个,他要求比1这个元素大1的(第二个样例),我的二分是找到 ==k跳出,这样就不可能等于0了,在网上又找到解决方法,如果 sum(mid) -sum(x)> k的时候 sum(mid-1) -sum(x) < k 说明 == k值就在mid里,只不过mid有多个。。。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1e5 + 5;
int c[maxn], a[maxn];
int lowbit(int k)
{
return k & -k;
}
void update(int pos, int val)
{
while(pos < maxn)
{
c[pos] += val;
pos += lowbit(pos);
}
}
int sum(int pos)
{
int ans = 0;
while(pos)
{
ans += c[pos];
pos -= lowbit(pos);
}
return ans;
}
int main()
{
int n, op, r, k;
while(~scanf("%d", &n))
{
memset(c, 0, sizeof(c));
memset(a, 0, sizeof(a));
while(n--)
{
scanf("%d", &op);
if(op == 0)
{
scanf("%d", &r);
a[r]++;
update(r, 1);
}
if(op == 1)
{
scanf("%d", &r);
if(!a[r]) printf("No Elment!\n");
else a[r]--, update(r, -1);
}
if(op == 2)
{
scanf("%d%d", &r, &k);
int left = r, right = maxn, flag = 0;
while(left < right)
{
int mid = (left + right) / 2;
if(sum(mid) - sum(r) > k)
{
if(sum(mid-1) - sum(r) < k)
{
printf("%d\n", mid);
flag = 1;
break;
}
right = mid;
}
if(sum(mid) - sum(r) < k) left = mid + 1;
if(sum(mid) - sum(r) == k)
{
if(a[mid]) {printf("%d\n", mid); flag = 1; break;}
else right = mid;
}
}
if(!flag) printf("Not Find!\n");
}
}
}
return 0;
}
二分其实还有另一种写法的。。如果sum(maxn) - sum(x) < k说明肯定没有足够的元素,否则肯定有。。肯定有的情况下,二分最后一个符合情况的mid就是答案。。。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1e5 + 5;
int c[maxn], a[maxn];
int lowbit(int k)
{
return k & -k;
}
void update(int pos, int val)
{
while(pos < maxn)
{
c[pos] += val;
pos += lowbit(pos);
}
}
int sum(int pos)
{
int ans = 0;
while(pos)
{
ans += c[pos];
pos -= lowbit(pos);
}
return ans;
}
int main()
{
int n, op, r, k;
while(~scanf("%d", &n))
{
memset(c, 0, sizeof(c));
memset(a, 0, sizeof(a));
while(n--)
{
scanf("%d", &op);
if(op == 0)
{
scanf("%d", &r);
a[r]++;
update(r, 1);
}
if(op == 1)
{
scanf("%d", &r);
if(!a[r]) printf("No Elment!\n");
else a[r]--, update(r, -1);
}
if(op == 2)
{
scanf("%d%d", &r, &k);
if(sum(maxn) - sum(r) < k) //说明肯定不符合情况
{
printf("Not Find!\n");
continue;
}
int left = r, right = maxn, flag = 0;
while(left < right)
{
int mid = (left + right) / 2;
if(sum(mid) - sum(r) < k) left = mid + 1;
else right = mid; //注意这里是=mid 不是mid-1,因为这里是符合情况的,可能前面是 == k,如果是 ==k mid就是答案了
}<span style="white-space:pre"> </span>//如果分情况多一点,不可能有 == k的情况就是mid - 1,因为mid已经不符合了,二分还要深刻理解啊!
printf("%d\n", right);
}
}
}
return 0;
}
关键代码:
int find_kth(int k){
int ans = 0, cnt = 0, i;
for (i = 20; i >= 0; i--){
ans += (1 << i);
if (ans >= maxn|| cnt + c[ans] >= k)
ans -= (1 << i);
else cnt += c[ans];
}
return ans + 1;
}