P4647 [IOI2007] sails 船帆
由题意可知,这个就是初始有 \(N\) 个为 \(0\) 的变量,有 \(M\) 次操作,让你在前 \(h\) 个里面选 \(k\) 个各 \(+1\)。求 \(\sum_{i=1}^N \frac {x_i \cdot (x_i-1)} 2\) 最小值。
可以发现,操作顺序对最后答案没有影响。
那么我们贪心得使得这 \(k\) 个变得更小更优秀,那么按照 \(h_i\) 排序,那就不用考虑选高处还是低处的问题。然后可以考虑平衡树,因为还需要分裂交换子树,那么考虑 FHQ-Treap。那么我们就可以线找到最小的 \(k\) 个,然后给他们打上tag,接着考虑,这些中的某些数可能大于后面的一段树,那么我还需要按照值把他们分裂后,再合并回去。假定第 \(k+1\) 个数为 \(x\) 那么就会被分成一下段数。
1.前 \(k\) 个加了之后小于等于 \(x\) 的。2.前 \(k\) 个加了之后大于 \(x\) 的(也就是 \(x+1\))。3.除了前 \(k\) 个以外的值为 \(x+1\) 的。4.除了前 \(k\) 个以外的大于 \(x+1\) 的。
然后按顺序合并一下,最后dfs一下统计答案就好了。
/*
Name:
Author: Gensokyo_Alice
Date:
Description:
*/
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <map>
#include <set>
using namespace std;
typedef long long ll;
const ll MAXN = (1LL << 20) + 10;
ll N, M, root, ans, tot, c[MAXN][2];
struct nod {
ll val, tag, siz, rd;
nod () {val = tag = siz = rd = 0;}
nod (ll _val, ll _tag, ll _siz, ll _rd):val(_val), tag(_tag), siz(_siz), rd(_rd) {}
} t[MAXN];
struct que {
ll h, k;
friend bool operator < (que a, que b) {return a.h < b.h;}
} q[MAXN];
void pushdown(ll);
ll get();
ll mer(ll, ll);
void split(ll, ll, ll&, ll&);
void split2(ll, ll, ll&, ll&);
void dfs(ll);
void add(ll, ll);
void pushup(ll);
int main() {
srand(time(0));
scanf("%lld", &N);
for (ll i = 1; i <= N; i++) scanf("%lld%lld", &q[i].h, &q[i].k);
sort(q+1, q+N+1);
for (ll i = 1; i <= N; i++) {
for (ll j = 1, k = q[i].h - q[i-1].h; j <= k; j++) {ll tem = get(); root = mer(tem, root);}
ll x, y, z, tmp;
split(root, q[i].k, x, y);
add(x, 1);
split(x, q[i].k-1, x, z);
tmp = t[z].val;
x = mer(x, z);
split2(x, tmp-1, x, z);
x = mer(x, y);
split2(x, tmp, x, y);
root = mer(mer(x, z), y);
}
dfs(root);
printf("%lld\n", ans);
return 0;
}
void dfs(ll n) {
pushdown(n);
if (c[n][0]) dfs(c[n][0]);
ans += (t[n].val + 1) * t[n].val / 2;
if (c[n][1]) dfs(c[n][1]);
}
ll get() {
t[++tot] = nod(-1, 0, 1, rand());
return tot;
}
ll mer(ll x, ll y) {
if (!x || !y) return x | y;
if (t[x].rd < t[y].rd) {
pushdown(x);
c[x][1] = mer(c[x][1], y);
pushup(x);
return x;
} else {
pushdown(y);
c[y][0] = mer(x, c[y][0]);
pushup(y);
return y;
}
}
void split(ll rt, ll k, ll &x, ll &y) {
if (!rt) {
x = y = 0;
return;
}
pushdown(rt);
if (t[c[rt][0]].siz < k) {
x = rt;
split(c[x][1], k - t[c[x][0]].siz - 1, c[x][1], y);
pushup(x);
} else {
y = rt;
split(c[y][0], k, x, c[y][0]);
pushup(y);
}
}
void split2(ll rt, ll k, ll &x, ll &y) {
if (!rt) {
x = y = 0;
return;
}
pushdown(rt);
if (t[rt].val <= k) {
x = rt;
split2(c[x][1], k, c[x][1], y);
pushup(x);
} else {
y = rt;
split2(c[y][0], k, x, c[y][0]);
pushup(y);
}
}
void pushup(ll x) {t[x].siz = t[c[x][0]].siz + t[c[x][1]].siz + 1;}
void pushdown(ll x) {
if (!x || t[x].tag == 0) return;
if (c[x][0]) add(c[x][0], t[x].tag);
if (c[x][1]) add(c[x][1], t[x].tag);
t[x].tag = 0;
}
void add(ll node, ll v) {
t[node].tag += v;
t[node].val += v;
}
希望我们都有一个光明的未来

浙公网安备 33010602011771号