树状数组这个真心想了好久,还是没想出来 %%% www.cppblog.com/Yuan/archive/2010/08/18/123871.html
树状数组求前缀和大于等于k的最大值,第一次看到这种方法,很神奇,就是没看懂= =
二分也是可以求的,不过感觉会慢一些……
思路就是把所有没有询问到的数压缩
例如如果n等于10 值询问到了 2, 7 大概是这样的
【1,2】【3,4,5,6,7】【8,9,10】
1 2 3
分成3块,最多分为q块,实现离散化。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std; const int N = ;
int op[N], a[N], b[N], p[N], no[N];
int n, q; struct BIT {
int arr[N];
int n;
int sum(int p) {
int ans = ;
while (p) {
ans += arr[p];
p -= lowbit(p);
}
return ans;
}
void add(int p, int v) {
while (p <= n) {
arr[p] += v;
p += lowbit(p);
}
}
int find(int k) { //在数组中找第一个大于等于k的位置
int pos = , cnt = ;
for (int i = ; i >= ; --i) {
pos += (<<i);
if (pos >= n || cnt + arr[pos] >= k) pos -= (<<i);
else cnt += arr[pos];
}
return pos+;
}
void init(int n) {
this->n = n;
memset(arr, , sizeof arr);
}
int lowbit(int x) {
return x&-x;
}
} bit; int main()
{
//freopen("in.txt", "r", stdin);
int T, cas = ;
scanf("%d", &T);
while (T--) {
printf("Case %d:\n", ++cas);
scanf("%d%d", &n, &q);
char ch[];
int idx = ;
for (int i = ; i <= q; ++i) {
scanf("%s%d", ch, &a[i]);
if (*ch == 'T') op[i] = ;
else if (*ch == 'Q') op[i] = ;
else op[i] = ;
if (op[i] < ) b[++idx] = a[i];
}
b[++idx] = n;
sort(b+, b++idx);
n = unique(b+, b++idx) - b - ;
bit.init(*q);
for (int i = ; i <= n; ++i) {
bit.add(q+i, b[i]-b[i-]);
no[q+i] = b[i]; // no[i] 数组i处的编号 原编号!!
p[i] = q+i; // p[i] 编号为i的位置
}
int top = q;
for (int i = ; i <= q; ++i) {
if (op[i] == ) {
int x = lower_bound(b+, b++n, a[i]) - b;
bit.add(p[x], -); // 要把x挪到顶端 p[x]位置的数字个数减少一个
no[p[x]]--; // x走了 剩下的是x-1
p[x] = top; // x的位置变成了top
bit.add(top, ); // top位置有一个数字x +1
no[top] = a[i];
top--;
} else if (op[i] == ) {
int x = lower_bound(b+, b++n, a[i]) - b;
printf("%d\n", bit.sum( p[ x ] ));
} else {
int pos = bit.find(a[i]);
int sp = bit.sum(pos);
if (sp == a[i]) printf("%d\n", no[pos]);
else printf("%d\n", no[pos]-(sp-a[i]));
}
}
}
return ;
}
Splay 再补……