1 条题解
-
0
自动搬运
来自洛谷,原作者为

zzxLLL
Retired搬运于
2025-08-24 22:42:34,当前版本为作者最后更新于2022-11-21 18:13:50,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
upd on 2023/10/22:修正了柿子。
很显然要二分 ,那么问题就是快速处理中间高度小于 的圆圈个数。
可以把一个区间分成三部分:
左端点所在三角形 ,右端点所在三角形 ,中间的三角形 。
然后分类讨论:
- 时:
说明左右端点在同个三角形内,我们可以快速计算高度小于 的圆圈个数。
int calc(int i, int l, int r, int h) { int v1, v2; if (b[i] == 0) v1 = l, v2 = r; if (b[i] == 1) v1 = a[i] - r + 1, v2 = a[i] - l + 1; if (h <= v1) return h * (r - l + 1); if (h > v2) return (v2 + v1) * (r - l + 1) / 2; return (v2 - h) * h + (h + v1) * (h - v1 + 1) / 2; }- 时:
比较麻烦,左右两边可以通过
calc函数快速计算,问题在于中间的完整三角形。直接计算符合条件的圆圈个数比较难,我们可以用总个数-不符合条件的个数。
设中间完整三角形高度大于h的高度为 ,那么不符合条件圆圈个数等于:
$\begin{aligned} & \frac{1}{2} \sum\limits_{i = 1}^k (h_i - h) (h_i - h + 1) \\&= \frac{1}{2} \sum\limits_{i = 1}^k (h_i^2 - 2h_ih + h^2 + h_i - h) \end{aligned}$
设 $S_1= \sum_{i=1}^{k}h_i , S_2= \sum_{i=1}^{k}h_i^{2}$,
那么原式 。
显然可以主席树维护,快速查询 ,进而计算出符合条件的圆圈个数。
#include<cmath> #include<cstdio> #include<algorithm> #define int long long using namespace std; const int M = 1e6 + 10; const int inf = 1000000; int L[M], R[M]; int pre[M], cnt_pre[M], a[M], b[M], n, m; int calc(int i, int l, int r, int h) { int v1, v2; if (b[i] == 0) v1 = l, v2 = r; if (b[i] == 1) v1 = a[i] - r + 1, v2 = a[i] - l + 1; if (h <= v1) return h * (r - l + 1); if (h > v2) return (v2 + v1) * (r - l + 1) / 2; return (v2 - h) * h + (h + v1) * (h - v1 + 1) / 2; } struct PersistentTree { int lc, rc, sum, sqs, cnt; //sum[k,k]=k sqs[k,k]=k*k cnt[k,k]=1 }tr[M << 3]; int rt[M], cntv; void pushup(int k) { tr[k].sum = tr[tr[k].lc].sum + tr[tr[k].rc].sum; tr[k].sqs = tr[tr[k].lc].sqs + tr[tr[k].rc].sqs; tr[k].cnt = tr[tr[k].lc].cnt + tr[tr[k].rc].cnt; } void update(int &k, int pre, int l, int r, int pos, int h) { tr[k = ++cntv] = tr[pre]; if (l == r) { tr[k].sum += h; tr[k].sqs += h * h; tr[k].cnt += 1; return; } int mid = (l + r) >> 1; if (pos <= mid) update(tr[k].lc, tr[pre].lc, l, mid, pos, h); else update(tr[k].rc, tr[pre].rc, mid + 1, r, pos, h); pushup(k); } int query_sum(int k, int pre, int L, int R, int l, int r) { if (L <= l and r <= R) return tr[k].sum - tr[pre].sum; int mid = (l + r) >> 1, ans = 0; if (L <= mid) ans += query_sum(tr[k].lc, tr[pre].lc, L, R, l, mid); if (R > mid) ans += query_sum(tr[k].rc, tr[pre].rc, L, R, mid + 1, r); return ans; } int query_sqs(int k, int pre, int L, int R, int l, int r) { if (L <= l and r <= R) return tr[k].sqs - tr[pre].sqs; int mid = (l + r) >> 1, ans = 0; if (L <= mid) ans += query_sqs(tr[k].lc, tr[pre].lc, L, R, l, mid); if (R > mid) ans += query_sqs(tr[k].rc, tr[pre].rc, L, R, mid + 1, r); return ans; } int query_cnt(int k, int pre, int L, int R, int l, int r) { if (L <= l and r <= R) return tr[k].cnt - tr[pre].cnt; int mid = (l + r) >> 1, ans = 0; if (L <= mid) ans += query_cnt(tr[k].lc, tr[pre].lc, L, R, l, mid); if (R > mid) ans += query_cnt(tr[k].rc, tr[pre].rc, L, R, mid + 1, r); return ans; } signed main() { scanf("%lld%lld", &n, &m); for (int i = 1; i <= n; i++) { scanf("%lld%lld", &a[i], &b[i]); update(rt[i], rt[i - 1], 1, inf, a[i], a[i]); pre[i] = pre[i - 1] + a[i]; cnt_pre[i] = cnt_pre[i - 1] + a[i] * (a[i] + 1) / 2; L[i] = pre[i - 1] + 1, R[i] = pre[i]; } for (int i = 1, l, r, v; i <= m; i++) { scanf("%lld%lld%lld", &l, &r, &v); int ll = lower_bound(pre + 1, pre + 1 + n, l) - pre; int rr = lower_bound(pre + 1, pre + 1 + n, r) - pre; int lb = 1, rb = inf, ans = -1; while (lb <= rb) { int mid = (lb + rb) >> 1; int res; if (ll == rr) res = calc(ll, l - L[ll] + 1, r - L[ll] + 1, mid); else { int tmp_sum = query_sum(rt[rr - 1], rt[ll], mid, inf, 1, inf) - query_sum(rt[rr - 1], rt[ll], mid, mid, 1, inf);//S1 int tmp_sqs = query_sqs(rt[rr - 1], rt[ll], mid, inf, 1, inf) - query_sqs(rt[rr - 1], rt[ll], mid, mid, 1, inf);//S2 int tmp_cnt = query_cnt(rt[rr - 1], rt[ll], mid, inf, 1, inf) - query_cnt(rt[rr - 1], rt[ll], mid, mid, 1, inf);//k res = (tmp_sqs - 2 * tmp_sum * mid + tmp_cnt * mid * mid + tmp_sum - tmp_cnt * mid) / 2; res = cnt_pre[rr - 1] - cnt_pre[ll] - res; res += calc(ll, l - L[ll] + 1, R[ll] - L[ll] + 1, mid) + calc(rr, 1, r - L[rr] + 1, mid); } if (res >= v) ans = mid, rb = mid - 1; else lb = mid + 1; } printf("%lld\n", ans); } return 0; }
- 1
信息
- ID
- 7974
- 时间
- 3000ms
- 内存
- 512MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者