【题解】LuoGu3871:[TJOI2010]中位数

原题传送门

法1 堆

用两个堆维护
较小的那部分用大根堆,较大的那部分用小根堆
每次保证大根堆中数的个数 s 1 s1 s1与小根堆的 s 2 s2 s2相比, s 1 = s 2 或 s 1 = s 2 + 1 s1=s2或s1=s2+1 s1=s2s1=s2+1
这样每次输出大根堆的根就行了

Code:

#include 
using namespace std;
int s1, s2, n;
priority_queue <int> q1;
priority_queue < int, vector <int>, greater <int> > q2;

inline int read(){
	int s = 0, w = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
	for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
	return s * w;
}

inline int get(){
	char c = getchar();
	for (; c != 'a' && c != 'm'; c = getchar());
	if (c == 'a') return 0; else return 1;
}

void add(int x){
	if (x <= q1.top()) q1.push(x), ++s1; else q2.push(x), ++s2; 
	while (s1 < s2) q1.push(q2.top()), q2.pop(), ++s1, --s2;
	while (s1 > s2 + 1) q2.push(q1.top()), q1.pop(), --s1, ++s2;
//	printf("%d %d %d %d\n", s1, q1.top(), s2, q2.top());
}

int main(){
	n = read();
	q1.push(read()), ++s1;
	for (int i = 2; i <= n; ++i) add(read());
	int T = read();
	while (T--) if (get()) printf("%d\n", q1.top()); else add(read());
	return 0;
}

法2 树状数组

发现上面那个方法其实无法维护删数,用树状数组可以解决
但是树状数组必须离线离散化,其实最好的方法是平衡树或者stl,但在联赛范围不需要知道

Code:

#include 
#define maxn 200010
using namespace std;
struct node{
	int x, val, opt, id;
}a[maxn];
int n, tree[maxn], p, m, val[maxn];

inline int read(){
	int s = 0, w = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
	for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
	return s * w;
}

inline int get(){
	char c = getchar();
	for (; c != 'a' && c != 'm'; c = getchar());
	if (c == 'a') return 0; else return 1;
}

bool cmp1(node x, node y){ return x.opt == y.opt ? x.val < y.val : x.opt < y.opt; }
bool cmp2(node x, node y){ return x.id < y.id; }
int lowbit(int x){ return x & -x; }
void upd(int x){ for (; x <= p; x += lowbit(x)) ++tree[x]; }
int query(int x){ int s = 0; for (; x; x -= lowbit(x)) s += tree[x]; return s; }

int find(int x){
	int l = 1, r = p, ans;
	while (l <= r){
		int mid = (l + r) >> 1;
	//	if (query(mid) == x) ans = mid;
		if (query(mid) >= x) r = mid - 1, ans = mid; else l = mid + 1;
	}
	return ans;
}

int main(){
	n = read();
	for (int i = 1; i <= n; ++i) a[i].opt = 0, a[i].val = read();
	m = read();
	for (int i = n + 1; i <= n + m; ++i){
		a[i].id = i;
		a[i].opt = get();
		if (!a[i].opt) a[i].val = read();
	}
	sort(a + 1, a + 1 + n + m, cmp1);
	a[0].val = a[1].val - 1;
	for (int i = 1; i <= n + m; ++i){
		if (a[i].opt) break;
		if (a[i].val != a[i - 1].val) ++p;
		a[i].x = p, val[p] = a[i].val;
	}
	sort(a + 1, a + 1 + n + m, cmp2);
	int s = 0;
	for (int i = 1; i <= n + m; ++i){
	//	printf("%d %d %d\n", a[i].opt, a[i].x, a[i].val);
		if (!a[i].opt) upd(a[i].x), ++s;
		else printf("%d\n", val[find((s + 1) >> 1)]);
	}
	return 0;
}

你可能感兴趣的:(题解,LuoGu,树状数组)