[NOI2010]超级钢琴

嘟嘟嘟


这题思路和今年省选D1T1特别像(不对,应该是D1T1和这道题特别像)。
反正省选前我是没做,做了考场上那题也不一定能写出来(虽然确实不难)。


这题就是先求一个前缀和,然后维护一个大根堆,里面存一个三元组((val, id, rk)),表示以(id)为右端点,长度在(L, R)之间的(sum[id] - sum[i])的第(rk)大的值是(val)
把堆中最大的取出来,再把第(rk + 1)放进队列里,这样循环(k)次就是答案。
求第(rk)大的最就是区间第(k)大,最直观的想法是主席树。也可以用st表做:因为每一次只是求排名比当前小1的,那么分治到两个子区间中查询最大值即可。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define enter puts("") 
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define In inline
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 5e5 + 5;
const int maxt = 2e7 + 5;
inline ll read()
{
	ll ans = 0;
	char ch = getchar(), last = ' ';
	while(!isdigit(ch)) last = ch, ch = getchar();
	while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
	if(last == '-') ans = -ans;
	return ans;
}
inline void write(ll x)
{
	if(x < 0) x = -x, putchar('-');
	if(x >= 10) write(x / 10);
	putchar(x % 10 + '0');
}

int n, K, L, R;
ll sum[maxn], T[maxn];
int l[maxn], r[maxn];

struct Tree
{
	int ls, rs, siz;
}t[maxt];
int root[maxn], tcnt = 0;
In void build(int& now, int L, int R, int id)
{
	++t[now = ++tcnt].siz;
	if(L == R) return;
	int mid = (L + R) >> 1;
	if(id <= mid) build(t[now].ls, L, mid, id);
	else build(t[now].rs, mid + 1, R, id);
}
In void insert(int old, int& now, int l, int r, int id)
{
	t[now = ++tcnt] = t[old];
	++t[now].siz;
	if(l == r) return;
	int mid = (l + r) >> 1;
	if(id <= mid) insert(t[old].ls, t[now].ls, l, mid, id);
	else insert(t[old].rs, t[now].rs, mid + 1, r, id);
}
In int query(int old, int now, int l, int r, int id)
{
	if(l == r) return l; 
	int mid = (l + r) >> 1, Sum = t[t[now].ls].siz - t[t[old].ls].siz;
	if(Sum >= id) return query(t[old].ls, t[now].ls, l, mid, id);
	else return query(t[old].rs, t[now].rs, mid + 1, r, id - Sum);
}

struct Node
{
	ll val; int id, rk;
	In bool operator < (const Node& oth)const
	{
		return val < oth.val;
	}
};
priority_queue<Node> q;

int main()
{
	n = read(), K = read(), L = read(), R = read();
	for(int i = 1; i <= n; ++i) sum[i] = sum[i - 1] + read(), T[i] = sum[i];
	sort(T + 1, T + n + 2);
	int _n = unique(T + 1, T + n + 2) - T - 1;
	build(root[1], 1, _n, lower_bound(T + 1, T + _n + 1, 0) - T);
	for(int i = 1; i <= n; ++i) 
		insert(root[i], root[i + 1], 1, _n, sum[i] = lower_bound(T + 1, T + _n + 1, sum[i]) - T);
	for(int i = 1; i <= n; ++i) l[i] = max(0, i - R), r[i] = i - L + 1;
	for(int i = 1; i <= n; ++i)
	{
		if(l[i] >= r[i]) continue;
		int tp = query(root[l[i]], root[r[i]], 1, _n, 1);
		q.push((Node){T[sum[i]] - T[tp], i, 1});	
	}
	ll ans = 0;
	for(int i = 1; i <= K; ++i)
	{
		Node nod = q.top(); q.pop();
		ans += nod.val;
		if(nod.rk == r[nod.id] - l[nod.id]) continue;
		int tp = query(root[l[nod.id]], root[r[nod.id]], 1, _n, nod.rk + 1);
		q.push((Node){T[sum[nod.id]] - T[tp], nod.id, nod.rk + 1});
	}
	write(ans), enter;
	return 0;
}
原文地址:https://www.cnblogs.com/mrclr/p/10793925.html