题意:
给出一个长度为 n (<=100000) 的序列,有q次操作,每次操作将最大的K个数取出来求和,然后将这K个数减1,再放回序列,求最后的答案。
题解:
不难想首先将序列从小到大排序,从最后取出K个数,然后区间求和,区间减1,可以发现很容易保证这个序列的单调性。
比如n = 6 K = 2 序列为 1 2 3 4 4 5 那么就应该修改成这样 1 2 3 3 4 4,那么就应该找出K个数中最小的那个数的前驱后继。
代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 1e5 + 7;
LL sum[N << 2], lz[N << 2], ans, mif[N << 2];
int n, ai[N], K, q;
#define mid (l + r >> 1)
#define lson o << 1, l, mid
#define rson o << 1 | 1, mid + 1, r
void build (int o, int l, int r)
{
if (l == r)
{
sum[o] = ai[l];
return;
}
build(lson);
build(rson);
sum[o] = sum[o << 1] + sum[o << 1 | 1];
}
void pushdown (int o, int l, int r)
{
sum[o << 1] += (mid - l + 1) * lz[o];
mif[o << 1] += (mid - l + 1) * lz[o];
lz[o << 1] += lz[o];
sum[o << 1 | 1] += (r - mid) * lz[o];
mif[o << 1 | 1] += (r - mid) * lz[o];
lz[o << 1 | 1] += lz[o];
lz[o] = 0;
}
void update (int o, int l, int r, int L, int R, int x)
{
if (l == L && r == R)
{
lz[o] += x;
mif[o] += (R - L + 1) * x;
sum[o] += (R - L + 1) * x;
return;
}
pushdown(o, l, r);
if (R <= mid) update(lson, L, R, x);
else if (L > mid) update(rson, L, R, x);
else update(lson, L, mid, x), update(rson, mid + 1, R, x);
sum[o] = sum[o << 1] + sum[o << 1 | 1];
mif[o] = mif[o << 1] + mif[o << 1 | 1];
}
LL query (int o, int l, int r, int L, int R)
{
if (l == L && r == R) return sum[o];
pushdown(o, l, r);
if (R <= mid) return query (lson, L, R);
else if (L > mid) return query (rson, L, R);
else return query (lson, L, mid) + query (rson, mid + 1, R);
}
int lazy (int o, int l, int r, int x)
{
if (l == r && l == x) return mif[o];
pushdown (o, l, r);
if (x <= mid) return lazy (lson, x);
else if (x > mid) return lazy (rson, x);
}
int find (int x)
{
int l = 1, r = n;
while (l < r)
{
if (ai[mid] + lazy(1, 1, n, mid) >= x) r = mid;
else l = mid + 1;
}
return l;
}
int main ()
{
scanf ("%d", &n);
for (int i = 1; i <= n; ++i) scanf ("%d", &ai[i]);
sort (ai + 1, ai + 1 + n);
build (1, 1, n);
scanf ("%d", &q);
while (q--)
{
scanf ("%d", &K);
int w = ai[n - K + 1] + lazy(1, 1, n, n - K + 1);
int x = find (w), y = find (w + 1);
if (ai[x] + lazy(1, 1, n, x) != ai[y] + lazy(1, 1, n, y))
{
ans += query (1, 1, n, x, x + K - n + y - 2);
ans += query (1, 1, n, y, n);
update (1, 1, n, x, x + K - n + y - 2, -1);
update (1, 1, n, y, n, -1);
}
else
{
ans += query (1, 1, n, x, x + K - 1);
update (1, 1, n, x, x + K - 1, -1);
}
}
cout << ans << endl;
return 0;
}
总结:
善于观察因为只减1,很容易就保证了序列的单调性呀~