BZOJ 2752: [HAOI2012]高速公路(road) (线段树) - Gemini Boy - ACM之路~
BZOJ 2752: [HAOI2012]高速公路(road) (线段树)
链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2752
概率背景的题,不过稍微想想,稍微推一推,就能得到公式。然后注意到只要用线段树维护3个sum就行了,sum1 费用和, sum2 下标乘以费用的和 sum3下标的平方乘以费用的和
PS:。。。在写线段树的时候被一个傻逼问题bug住了好久,,调了好久。好吧 我就是煞笔
2版线段树的代码。
#include <cstdio> #include <cstring> #include <string> #include <iostream> #include <algorithm> using namespace std; const int maxn = 100100; long long sumo[maxn], sump[maxn]; struct SegNode { int left, right; long long sum1, sum2, sum3; long long add; int mid() { return (left + right) >> 1; } long long size() { return (right - left + 1); } }; struct SegmentTree { SegNode tree[maxn*5]; void pushUp(int idx) { tree[idx].sum1 = tree[idx<<1].sum1 + tree[idx<<1|1].sum1; tree[idx].sum2 = tree[idx<<1].sum2 + tree[idx<<1|1].sum2; tree[idx].sum3 = tree[idx<<1].sum3 + tree[idx<<1|1].sum3; } void pushDown(int idx) { if (tree[idx].add) { long long add = tree[idx].add; int right1 = tree[idx<<1].right; int left1 = tree[idx<<1].left; int right2 = tree[idx<<1|1].right; int left2 = tree[idx<<1|1].left; tree[idx].add = 0; tree[idx<<1].sum1 += tree[idx<<1].size() * add; tree[idx<<1|1].sum1 += tree[idx<<1|1].size() * add; tree[idx<<1].sum2 += (sumo[right1] - sumo[left1-1]) * add; tree[idx<<1|1].sum2 += (sumo[right2] - sumo[left2-1]) * add; tree[idx<<1].sum3 += (sump[right1] - sump[left1-1]) * add; tree[idx<<1|1].sum3 += (sump[right2] - sump[left2-1]) * add; tree[idx<<1].add += add; tree[idx<<1|1].add += add; } } void build(int left, int right, int idx) { tree[idx].left = left; tree[idx].right = right; tree[idx].sum1 = 0; tree[idx].sum2 = 0; tree[idx].sum3 = 0; tree[idx].add = 0; if (left == right) return ; int mid = tree[idx].mid(); build(left, mid, idx<<1); build(mid+1, right, idx<<1|1); } void update(int left, int right, int idx, long long value) { if (tree[idx].left == left && tree[idx].right == right) { tree[idx].add += value; tree[idx].sum1 += tree[idx].size() * value; tree[idx].sum2 += (sumo[right] - sumo[left-1]) * value; tree[idx].sum3 += (sump[right] - sump[left-1]) * value; return ; } pushDown(idx); int mid = tree[idx].mid(); if (right <= mid) update(left, right, idx<<1, value); else if (left > mid) update(left, right, idx<<1|1, value); else { update(left, mid, idx<<1, value); update(mid+1, right, idx<<1|1, value); } pushUp(idx); } long long query(int left, int right, int idx, int L, int R) { if (tree[idx].left == left && tree[idx].right == right) { //printf("%d %d %d\n", idx, left, right); return (R + L - 1) * tree[idx].sum2 - tree[idx].sum3 - ((long long)L * R - R) * tree[idx].sum1; } pushDown(idx); int mid = tree[idx].mid(); if (right <= mid) return query(left, right, idx<<1, L, R); else if (left > mid) return query(left, right, idx<<1|1, L, R); else { return (query(left, mid, idx<<1, L, R) + query(mid+1, right, idx<<1|1, L, R)); } } }; SegmentTree tree; int N, M; long long gcd(long long a, long long b) { return b ? gcd(b, a % b) : a; } void init() { memset(sumo, 0, sizeof(sumo)); memset(sump, 0, sizeof(sump)); for (int i = 1; i < maxn; i++) sumo[i] = sumo[i-1] + i; for (int i = 1; i < maxn; i++) sump[i] = sump[i-1] + (long long)i * i; scanf("%d %d", &N, &M); tree.build(1, N, 1); } void work() { char op[19]; for (int i = 0; i < M; i++) { scanf("%s", op); if (op[0] == 'C') { int x, y; long long z; scanf("%d %d %lld", &x, &y, &z); tree.update(x, y-1, 1, z); } else { int x, y; scanf("%d %d", &x, &y); long long tmp = tree.query(x, y, 1, x, y); long long tem = (long long)(y - x + 1) * (y - x) / 2; long long ans = gcd(tmp, tem); printf("%lld/%lld\n", tmp / ans, tem / ans); } } } int main() { init(); work(); return 0; }
#include <cstdio> #include <cstring> #include <string> #include <iostream> #include <algorithm> using namespace std; const int maxn = 100100; long long sumo[maxn], sump[maxn]; struct SegNode { int left, right; long long sum1, sum2, sum3; long long add; }; struct SegmentTree { SegNode tree[maxn*5]; void pushUp(int idx) { tree[idx].sum1 = tree[idx<<1].sum1 + tree[idx<<1|1].sum1; tree[idx].sum2 = tree[idx<<1].sum2 + tree[idx<<1|1].sum2; tree[idx].sum3 = tree[idx<<1].sum3 + tree[idx<<1|1].sum3; } void pushDown(int idx, int left, int right) { if (tree[idx].add) { long long add = tree[idx].add; tree[idx].add = 0; tree[idx].sum1 += (right - left + 1) * add; tree[idx].sum2 += (sumo[right] - sumo[left-1]) * add; tree[idx].sum3 += (sump[right] - sump[left-1]) * add; if (left == right) return ; tree[idx<<1].add += add; tree[idx<<1|1].add += add; } } void update(int L, int R, int left, int right, int idx, long long value) { pushDown(idx, L, R); if (L >= left && R <= right) { tree[idx].add += value; return ; } int mid = (L + R) >> 1; if (left <= mid) update(L, mid, left, right, idx<<1, value); if (right >= mid+1) update(mid+1, R, left, right, idx<<1|1, value); pushDown(idx<<1, L, mid); pushDown(idx<<1|1, mid+1, R); pushUp(idx); } long long query(int L, int R, int left, int right, int idx) { pushDown(idx, L, R); if (L >= left && R <= right) { printf("%d %d %d\n", idx, left, right); return (right + left - 1) * tree[idx].sum2 - tree[idx].sum3 - ((long long)left * right - right) * tree[idx].sum1; } int mid = (L + R) >> 1; long long ans = 0; if (left <= mid) ans += query(L, mid, left, right, idx<<1); if (right >= mid + 1) ans += query(mid+1, R, left, right, idx<<1|1); return ans; } }; SegmentTree tree; int N, M; long long gcd(long long a, long long b) { return b ? gcd(b, a % b) : a; } void init() { memset(sumo, 0, sizeof(sumo)); memset(sump, 0, sizeof(sump)); for (int i = 1; i < maxn; i++) sumo[i] = sumo[i-1] + i; for (int i = 1; i < maxn; i++) sump[i] = sump[i-1] + (long long)i * i; scanf("%d %d", &N, &M); } void work() { char op[19]; for (int i = 0; i < M; i++) { scanf("%s", op); if (op[0] == 'C') { int x, y; long long z; scanf("%d %d %lld", &x, &y, &z); tree.update(1, N, x, y-1, 1, z); } else { int x, y; scanf("%d %d", &x, &y); long long tmp = tree.query(1, N, x, y, 1); long long tem = (long long)(y - x + 1) * (y - x) / 2; long long ans = gcd(tmp, tem); printf("%lld/%lld\n\n", tmp / ans, tem / ans); } } } int main() { init(); work(); return 0; }