[51Nod-1494](权值线段数)

#define lk k << 1
#define rk k << 1 | 1
#define mk (l + r) >> 1
const int maxn = 1e5 + 10;

struct node {//权值线段树
	int num, sum;
}tree[maxn << 2];
int id[maxn], cnt;
bool vis[maxn];
priority_queue< int, vector<int>, greater<int> >q[maxn];//升序,小顶堆

bool cmp(int x, int y) {
	return q[x].size() > q[y].size();
}

void push(int k) {
	tree[k].num = tree[lk].num + tree[rk].num;
	tree[k].sum = tree[lk].sum + tree[rk].sum;
}

void updata(int k, int l, int r, int y, int w) {
	if (l == r) {
		tree[k].num += w;
		tree[k].sum += w * y;
		return;
	}

	int mid = mk;
	if (mid >= y)	updata(lk, l, mid, y, w);
	else	updata(rk, mid + 1, r, y, w);

	push(k);
}

int query(int k, int l, int r, int len) {//查询区间第len大的数,求和[1, len]
	if (len <= 0)	return 0;
	if (l == r)	return len * l;

	int ans = 0;
	int mid = mk;
	if (tree[lk].num <= len) {
		ans += tree[lk].sum;
		ans += query(rk, mid + 1, r, len - tree[lk].num);
	}
	else	ans += query(lk, l, mid, len);

	return ans;
}

int main() {
	int n, start = 0, t1, t2;
	scanf("%d", &n);

	for (int i = 0; i < n; ++i) {
		scanf("%d %d", &t1, &t2);
		if (!t1) {
			start++;//start 是我一开始就有的选票
			continue;
		}

		q[t1].push(t2);
		if (!vis[t1]) {
			id[cnt++] = t1;
			vis[t1] = 1;
		}
		updata(1, 0, 10000, t2, 1);
	}

	sort(id, id + cnt, cmp);
	int ans = 1e10, res = 0, num = 0;
	int limit = max(start, 1);
	for (int i = n; i >= limit; --i) {//这个i是 枚举假设我i张选票时获胜,其他人的票要小于i
		for (int j = 0; j < cnt; ++j) {//所以先令所有其他候选人的票小于i,然后我的选票不足i的话再从所以票中拿小的
			int temp = id[j];
			int sz = q[temp].size();
			if (sz < i)	break;

			while (sz >= i) {
				sz--;
				int now = q[temp].top();
				q[temp].pop();
				updata(1, 0, 10000, now, -1);
				res += now;
				num++;
			}
		}
		ans = min(ans, res + query(1, 0, 10000, i - num - start));
	}

	printf("%d\n", ans);
	return 0;
}



posted @ 2020-10-06 11:37  wansheking  阅读(91)  评论(0)    收藏  举报