发布时间:2025-12-09 11:50:04 浏览次数:1
考场上写了二分 + 树状数组。
没想到可以再二分一次于是加了个 set,水了 60。
当时还不知道线段树上二分这种傻逼玩意= =
今日学到虚脱。
简不动,简不动。
读完题发现全是废话。可总结出下面几个结论:
由结论 2,考虑先离散化温度。
考虑答案的单调性,前缀随温度递增,后缀随温度递减。
答案为前后缀最小的一方,显然为一关于温度的单峰函数。
首先想到二分温度,再用树状数组求得前缀后缀进行检查。
复杂度 \(O(Q\log^2 Q)\),期望得分 \(60pts\)。
发现过不去,考虑科技。
//知识点:树状数组上二分 /*By:Luckyblock*/#include <algorithm>#include <cstdio>#include <ctype.h>#include <cstring>#define ll long long#define lowbit(x) (x&-x)const int kMaxn = 2e6 + 10;//=============================================================struct Que { int opt, t, x, y, k;} q[kMaxn];int data_num, data[kMaxn];int allfire, pos, ans;//=============================================================inline int read() { int f = 1, w = 0; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1; for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0'); return f * w;}void GetMax(int &fir, int sec) { if (sec > fir) fir = sec;}void GetMin(int &fir, int sec) { if (sec < fir) fir = sec;}struct BitTree { int t[kMaxn]; void Modify(int pos_, int val_) { for (; pos_ < kMaxn; pos_ += lowbit(pos_)) t[pos_] += val_; } int Query(int pos_) { int ret = 0; for (; pos_; pos_ -= lowbit(pos_)) ret += t[pos_]; return ret; }} ice, fire;void Prepare(int Q) { for (int i = 1; i <= Q; ++ i) { q[i].opt = read(); if (q[i].opt == 1) { q[i] = (Que) {q[i].opt, read(), read(), read()}; data[++ data_num] = q[i].x; } else { q[i].k = read(); } } std :: sort(data + 1, data + data_num + 1); data_num = std :: unique(data + 1, data + data_num + 1) - data - 1; for (int i = 1; i <= Q; ++ i) { if (q[i].opt) q[i].x = std :: lower_bound(data + 1, data + data_num + 1, q[i].x) - data; }}void Query() { int len = 0, lsum = 0, rsum = 0; for (int i = 20; i >= 0; -- i) { int l = (1 << i); int newlsum = lsum + ice.t[len + l]; int newrsum = allfire - rsum - fire.t[len + l]; if (len + l <= data_num && newlsum < newrsum) { len += l; lsum += ice.t[len], rsum += fire.t[len]; } } int ans1 = std :: min(lsum, allfire - rsum); int ans2 = std :: min(ice.Query(len + 1), allfire - fire.Query(len)); if (ans1 > ans2) { pos = len, ans = ans1; return ; } ans = ans2; len = 0, lsum = 0, rsum = 0; for (int i = 20; i >= 0; -- i) { int l = (1 << i); int newlsum = lsum + ice.t[len + l]; int newrsum = allfire - rsum - fire.t[len + l]; if (len + l <= data_num && (newlsum < newrsum || std :: min (newlsum, newrsum) == ans)) { len += l; lsum += ice.t[len], rsum += fire.t[len]; } pos = len; }}//=============================================================int main() { int Q = read(); Prepare(Q); for (int i = 1; i <= Q; ++ i) { int opt = q[i].opt, t, x, y, k; if (opt == 1) { t = q[i].t, x = q[i].x, y = q[i].y; if (! t) ice.Modify(x, y); else fire.Modify(x, y), allfire += y; } else { int k = q[i].k; t = q[k].t, x = q[k].x, y = q[k].y; if (! t) ice.Modify(x, - y); else fire.Modify(x, - y), allfire -= y; } Query(); if (ans) printf("%d %d\n", data[pos + 1], 2 * ans); else printf("Peace\n"); } return 0;}这里是没写完常数过大过不去就弃了的的线段树二分。
还差一步 找到最大的相等的一段。
#include <algorithm>#include <cstdio>#include <ctype.h>#include <cstring>#include <map>#define ll long long#define ls (lson[now_])#define rs (rson[now_])#define allfire (sum[1][1])const int kMaxn = 2e6 + 10;const int kInf = 2e9;//=============================================================int Q, sumfire, sumice, ans1, ans2, q[kMaxn][3];//0 冰 1 火 int root, node_num, sum[kMaxn << 2][2], lson[kMaxn << 2], rson[kMaxn << 2];std :: map <int, int> fire;//=============================================================inline int read() { int f = 1, w = 0; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1; for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0'); return f * w;}void GetMax(int &fir, int sec) { if (sec > fir) fir = sec;}void GetMin(int &fir, int sec) { if (sec < fir) fir = sec;}void Pushup(int now_) { sum[now_][0] = sum[ls][0] + sum[rs][0]; sum[now_][1] = sum[ls][1] + sum[rs][1];}void Modify(int &now_, int L_, int R_, int type, int pos_, int val_) { if (! now_) now_ = ++ node_num; sum[now_][type] += val_; if (L_ == R_) return ; int mid = (L_ + R_) >> 1; if (pos_ <= mid) Modify(ls, L_, mid, type, pos_, val_); else Modify(rs, mid + 1, R_, type, pos_, val_);// Pushup(now_); }int QueryPos(int now_, int L_, int R_, int sum1_, int sum2_) { if (L_ == R_) return sum1_ + sum[now_][0] <= sum2_ ? L_ : 0; int mid = (L_ + R_) >> 1, ret = 0; if (sum1_ + sum[ls][0] < sum2_ - sum[ls][1] + fire[mid]) { //判断 mid 合法性 ret = mid; GetMax(ret, QueryPos(rs, mid + 1, R_, sum1_ + sum[ls][0], sum2_- sum[ls][1])); } else { GetMax(ret, QueryPos(ls, L_, mid, sum1_, sum2_)); } return ret;}void QuerySum(int now_, int L_, int R_, int pos_) { int mid = (L_ + R_) >> 1; if (pos_ < mid) { QuerySum(ls, L_, mid, pos_); return ; } sumice += sum[ls][0], sumfire -= sum[ls][1]; if (pos_ > mid) QuerySum(rs, mid + 1, R_, pos_);}//=============================================================int main() { Q = read(); for (int i = 1; i <= Q; ++ i) { int opt = read(), t, x, y; if (opt == 1) { t = q[i][0] = read(), x = q[i][1] = read(), y = q[i][2] = read(); Modify(root, 1, kInf, t, x, y); if (t) fire[x] += y; } else { int k = read(); t = q[k][0], x = q[k][1], y = q[k][2]; Modify(root, 1, kInf, t, x, - y); if (t) fire[x] -= y; } int pos = ans1 = QueryPos(root, 1, kInf, 0, allfire); sumice = 0, sumfire = allfire + fire[pos]; QuerySum(1, 1, kInf, pos); ans2 = sumice, sumice = 0, sumfire = allfire + fire[pos + 1]; QuerySum(1, 1, kInf, pos + 1); if (sumfire >= ans2) { ans1 = pos + 1, ans2 = sumfire; } if (! ans2) printf("Peace\n"); else printf("%d %d\n", ans1, 2 * ans2); } return 0;}