LOJ3299 【2020联合省选】冰火战士
Description
有两组二元组, 每次添加或者删除两组中的一个
求一个 使得
最大
如果对于任意一个 都不能满足 中的俩值不为 ,输出
Solution
首先观察题目,发现是个 型函数求 最值问题
然后本质上就转化成了找一个函数的峰
我们可以考虑将两个函数作差之后在线段树上二分做,但是发现这东西常数是很大的
(啊这里要离散化,然后仍到一个线段树上面就能做了)
最后是卡常神器: 倍增
考虑到我们只是维护前缀和这样的形式,所以我们可以考虑维护一个前缀和的树状数组,然后在上面倍增找到 函数的最值
这种手段常用于维护一个前缀和然后求满足某条件的
Code
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define For(i, a, b) for (register int i = a; i <= b; ++i)
#define reg register
#define Down(i, a, b) for (register int i = a; i >= b; --i)
namespace yspm {
inline int read() {
int res = 0, f = 1;
char k;
while (!isdigit(k = getchar()))
if (k == '-')
f = -1;
while (isdigit(k)) res = res * 10 + k - '0', k = getchar();
return res * f;
}
const int N = 2e6 + 10;
struct opt {
int typ, x, y, z;
} a[N];
int b[N<<1], m, T;
struct BIT {
int c[N << 1];
inline int lowbit(int x) { return x & (-x); }
inline void add(int x, int d) {
for (; x <= m; x += lowbit(x)) c[x] += d;
return ;
}
inline int calc(int x) {
int res = 0;
for (; x; x -= lowbit(x)) res += c[x];
return res;
}
} T0, T1;
inline int calc1() {
reg int now = 0, ans = 0;
Down(i, 22, 0)
if (ans + (1 << i) > m) continue;
else if (now + T0.c[ans + (1 << i)] - T1.c[ans + (1 << i)] < 0)
ans += 1 << i,now += T0.c[ans] - T1.c[ans];
return ans;
}
inline int calc2(int x) {
reg int now = 0, ans = 0;
Down(i, 22, 0)
if (ans + (1 << i) > m) continue;
else if (now + T1.c[ans + (1 << i)] >= x)
ans += (1 << i), now += T1.c[ans];
return ans;
}
signed main() {
//freopen("1.in","r",stdin);
T = read();
int id;
For(i, 1, T) {
a[i].typ = read();
if (a[i].typ - 1)
a[i] = a[read()], a[i].typ = 2;
else
a[i].x = read(), a[i].y = read(), a[i].z = read();
b[++m] = a[i].y;
b[++m] = a[i].y + 1;
}
sort(b + 1, b + m + 1);
m = unique(b + 1, b + m + 1) - b - 1;
For(i, 1, T) a[i].y = lower_bound(b + 1, b + m + 1, a[i].y) - b;
For(i, 1, T) {
if (a[i].x == 0)
T0.add(a[i].y, a[i].typ == 1 ? a[i].z : -a[i].z);
else
{
T1.add(1, a[i].typ == 1 ? a[i].z : -a[i].z);
T1.add(a[i].y + 1, a[i].typ == 1 ? -a[i].z : a[i].z);
}
int r1 = calc1(), ans1 = T0.calc(r1), ans2 = 0;
if (r1 + 1 <= m)
ans2 = T1.calc(r1 + 1);
if (ans1==0 && ans2==0)
puts("Peace");
else if (ans2 >= ans1)
printf("%lld %lld\n", b[calc2(ans2)], ans2 << 1);
else
printf("%lld %lld\n", b[r1], ans1 << 1);
}
return 0;
}
} // namespace yspm
signed main() { return yspm::main(); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律