「SDOI2017」相关分析
题目链接:https://loj.ac/problem/2005
题解:
把上面的式子拆掉,把下面的式子拆掉。
发现所有的东西都能用线段树暴力维护。
代码:
#include <bits/stdc++.h> #define N 100010 #define ls p << 1 #define rs p << 1 | 1 using namespace std; typedef double db; typedef double ll; ll sum[N << 2], tagx1[N << 2], tagx2[N << 2], tagy1[N << 2], tagy2[N << 2], sum2[N << 2]; bool tag1[N << 2], tag2[N << 2]; ll sumx[N << 2], sumy[N << 2]; char *p1, *p2, buf[100000]; #define nc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1 ++ ) int rd() { int x = 0, f = 1; char c = nc(); while (c < 48) { if (c == '-') f = -1; c = nc(); } while (c > 47) { x = (((x << 2) + x) << 1) + (c ^ 48), c = nc(); } return x * f; } inline void pushup(int p) { sum[p] = sum[ls] + sum[rs]; sumx[p] = sumx[ls] + sumx[rs]; sumy[p] = sumy[ls] + sumy[rs]; sum2[p] = sum2[ls] + sum2[rs]; } void pls1(int l, int r, int s, int t, int p) { int L = r - l + 1; sum[p] += (ll)t * sumx[p] + (ll)s * sumy[p] + (ll)s * t * L; sum2[p] += sumx[p] * s * 2 + (ll)s * s * L; sumx[p] += (ll)s * L; sumy[p] += (ll)t * L; if (tag2[p]) { tagx2[p] += s; tagy2[p] += t; } else { tagx1[p] += s; tagy1[p] += t; tag1[p] = true; } } inline ll bfr2(int x) { return (ll)x * (x + 1) * (2 * x + 1) / 6; } inline ll bfr1(int x) { return (ll)x * (x + 1) / 2; } void pls2(int l, int r, int s, int t, int p) { int L = r - l + 1; sum[p] = bfr2(r) - bfr2(l - 1) + (ll)(s + t) * (bfr1(r) - bfr1(l - 1)) + (ll)L * s * t; sum2[p] = bfr2(r) - bfr2(l - 1) + (ll)2 * s * (bfr1(r) - bfr1(l - 1)) + (ll)L * s * s; sumx[p] = bfr1(r) - bfr1(l - 1) + (ll)L * s; sumy[p] = bfr1(r) - bfr1(l - 1) + (ll)L * t; tag1[p] = false; tagx1[p] = tagy1[p] = 0; tag2[p] = true; tagx2[p] = s; tagy2[p] = t; } inline void pushdown(int l, int r, int p) { if (tag1[p]) { int mid = (l + r) >> 1; pls1(l, mid, tagx1[p], tagy1[p], ls); pls1(mid + 1, r, tagx1[p], tagy1[p], rs); tagx1[p] = tagy1[p] = 0; tag1[p] = false; } if (tag2[p]) { int mid = (l + r) >> 1; pls2(l, mid, tagx2[p], tagy2[p], ls); pls2(mid + 1, r, tagx2[p], tagy2[p], rs); tagx2[p] = tagy2[p] = 0; tag2[p] = false; } } void update1(int x, int y, int s, int t, int l, int r, int p) { if (x <= l && r <= y) { pls1(l, r, s, t, p); return; } int mid = (l + r) >> 1; pushdown(l, r, p); if (x <= mid) { update1(x, y, s, t, l, mid, ls); } if (mid < y) { update1(x, y, s, t, mid + 1, r, rs); } pushup(p); } void update2(int x, int y, int s, int t, int l, int r, int p) { if (x <= l && r <= y) { pls2(l, r, s, t, p); return; } int mid = (l + r) >> 1; pushdown(l, r, p); if (x <= mid) { update2(x, y, s, t, l, mid, ls); } if (mid < y) { update2(x, y, s, t, mid + 1, r, rs); } pushup(p); } ll queryx1(int x, int y, int l, int r, int p) { if (x <= l && r <= y) { return sumx[p]; } int mid = (l + r) >> 1; ll ans = 0; pushdown(l, r, p); if (x <= mid) { ans += queryx1(x, y, l, mid, ls); } if (mid < y) { ans += queryx1(x, y, mid + 1, r, rs); } return ans; } ll queryy1(int x, int y, int l, int r, int p) { if (x <= l && r <= y) { return sumy[p]; } int mid = (l + r) >> 1; ll ans = 0; pushdown(l, r, p); if (x <= mid) { ans += queryy1(x, y, l, mid, ls); } if (mid < y) { ans += queryy1(x, y, mid + 1, r, rs); } return ans; } ll query(int x, int y, int l, int r, int p) { if (x <= l && r <= y) { return sum[p]; } int mid = (l + r) >> 1; ll ans = 0; pushdown(l, r, p); if (x <= mid) { ans += query(x, y, l, mid, ls); } if (mid < y) { ans += query(x, y, mid + 1, r, rs); } return ans; } ll query2(int x, int y, int l, int r, int p) { if (x <= l && r <= y) { return sum2[p]; } int mid = (l + r) >> 1; ll ans = 0; pushdown(l, r, p); if (x <= mid) { ans += query2(x, y, l, mid, ls); } if (mid < y) { ans += query2(x, y, mid + 1, r, rs); } return ans; } ll a1[N], a2[N]; void build(int l, int r, int p) { if (l == r) { sum[p] = a1[l] * a2[l]; sum2[p] = a1[l] * a1[l]; sumx[p] = a1[l]; sumy[p] = a2[l]; return; } int mid = (l + r) >> 1; build(l, mid, ls); build(mid + 1, r, rs); pushup(p); } int main() { // freopen("gold.in", "r", stdin); // freopen("gold.out", "w", stdout); int n = rd(), Q = rd(); for (int i = 1; i <= n; i ++ ) { a1[i] = rd(); } for (int i = 1; i <= n; i ++ ) { a2[i] = rd(); } build(1, n, 1); while (Q -- ) { int opt = rd(); if (opt == 1) { int l = rd(), r = rd(); db Up; int L = r - l + 1; Up = query(l, r, 1, n, 1); Up -= (db)queryx1(l, r, 1, n, 1) * queryy1(l, r, 1, n, 1) / L; db Down; Down = query2(l, r, 1, n, 1); Down -= (db)queryx1(l, r, 1, n, 1) * queryx1(l, r, 1, n, 1) / L; printf("%.10lf ", Up / Down); } else if (opt == 2) { int l = rd(), r = rd(), s = rd(), t = rd(); update1(l, r, s, t, 1, n, 1); } else { int l = rd(), r = rd(), s = rd(), t = rd(); update2(l, r, s, t, 1, n, 1); } } return 0; }
小结:对拍的时候要记得,数据尽量和题面吻合,不然容易出一些奇奇怪怪的错误。比如说这个题考试的时候,我就有个值忘记开$long long$,对拍没拍出来因为我保证数据非常小。