P6619 冰火战士
咱就是说,一道树桩数组好题。
作前缀和可以得到冰战士的能量贡献,后缀和得到火战士的能量贡献。
每时每刻冰战士能贡献的最大能量是单调递增的,而火战士是单调递减的。
作 $f(x)$ 为冰战士的能量贡献, $g(x)$ 为火战士的能量贡献,$Q$ 为温度集合。得到:$$ans \gets \max_{i \in Q} \min \left \{ f(i), g(i) \right \} $$
作图可知答案函数为单峰函数,看似可以用三分,但是它并不严格单调,即存在某个区间,其函数值都相同,所以没办法三分。换个角度,我们可以在 $f(x)$, $g(x)$ 上二分找出最大的满足 $f(x) \le g(x)$ 的 $k$,然后再在 $g(x)$ 上找到最大的 $k^{'}$ 满足 $g(k + 1) = g(k^{'})$,比较俩点答案,输出即可。
考虑实现,如果我们使用数据结构维护前/后缀和,再套二分。那么这样时间复杂度是 $O(n\log^2 n)$ 的,铁定过不去。但是树状树组有一个很神奇的性质:$p[i + 2^p]$ 维护了 $ \left [ i,i+2^p \right ] $ 的所有信息。据此我们可以直接在树状树组上倍增,单次时间复杂度降至 $O(\log n)$。
实际实现中我们可以在火战士树状树组的第一位存下所有贡献,在相应位置加上负能量值,就可以用前缀实现后缀了。
小清新的代码实现:
#include<bits/stdc++.h>
using namespace std;
#define lb(x) (x & (-x))
#define rp(i, a, b) for(int i = a;i <= b;i++)
const int N = 2e6 + 50;
struct BIT {
int c[N << 2], len;
void add(int x, int v) {
for(; x <= len ; x += lb(x)) c[x] += v;
}
int query(int x) {
int ans = 0;
for(; x ; x -= lb(x)) ans += c[x];
return ans;
}
}tf, ti;
struct node { int opt, t, x, y, k; };
int Q, tot;
int lg[N], lsh[N];
node oper[N];
int half_search() {
int p = 0;
int sumi = 0, sumf = 0;
for(int t = 1 << lg[tot] ; t >= 1 ; t >>= 1) {
if(p + t <= tot && sumi + ti.c[p +t] <= sumf + tf.c[p + t]){
p += t;
sumi += ti.c[p];
sumf += tf.c[p];
}
}
return p;
}
int self_search(int p) {
if(p > tot) return 0;
int sumt, sumf = tf.query(p);
sumt = p = 0;
for(int t = 1 << lg[tot]; t >= 1 ; t >>= 1) {
if(p + t <= tot && sumt + tf.c[p + t] >= sumf) {
p += t;
sumt += tf.c[p];
}
}
return p;
}
int main() {
scanf("%d", &Q);
rp(i, 1, Q) {
scanf("%d", &oper[i].opt);
if(oper[i].opt == 1) scanf("%d %d %d", &oper[i].t, &oper[i].x, &oper[i].y), lsh[++tot] = oper[i].x;
else scanf("%d", &oper[i].k);
}
sort(lsh + 1, lsh + tot + 1);
tot = unique(lsh + 1, lsh + tot + 1) - lsh - 1;
rp(i, 1, Q) oper[i].x = lower_bound(lsh + 1, lsh + tot + 1, oper[i].x) - lsh;
lg[0] = -1;
rp(i, 1, tot) lg[i] = lg[i >> 1] + 1;
tf.len = ti.len = tot;
rp(i, 1, Q) {
int id = (oper[i].opt == 1 ? i : oper[i].k);
int tc = (oper[i].opt == 1 ? 1 : -1);
if(oper[id].t == 0)
ti.add(oper[id].x, oper[id].y * tc);
else
tf.add(1, oper[id].y * tc),
tf.add(oper[id].x + 1, -oper[id].y* tc);
int rk = half_search();
int rkk = self_search(rk + 1);
int ans1 = ti.query(rk) * 2;
int ans2 = tf.query(rkk) * 2;
if(max(ans1, ans2) == 0) printf("Peace\n");
else if(ans1 > ans2) printf("%d %d\n", lsh[rk], ans1);
else printf("%d %d\n", lsh[rkk], ans2);
}
return 0;
}

浙公网安备 33010602011771号