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; }
BZOJ 1798: [Ahoi2009]Seq 维护序列seq
http://www.lydsy.com/JudgeOnline/problem.php?id=1798
题意很简单,就是维护区间和,然后区间加一个值,区间乘以一个值。
做法就是维护 a * x + b 这个统计量,别的就是普通的线段树~
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std; const int maxn = 101000; long long value[maxn], mod; struct SegNode { int left, right; long long sum, add, mul; int mid() { return (left + right) >> 1; } int size() { return right - left + 1; } }; struct SegmentTree { SegNode tree[maxn*5]; void pushUp(int idx) { tree[idx].sum = (tree[idx<<1].sum + tree[idx<<1|1].sum) % mod; } void pushDown(int idx) { tree[idx<<1].add = (tree[idx].mul % mod * tree[idx<<1].add % mod + tree[idx].add) % mod; tree[idx<<1|1].add = (tree[idx].mul % mod * tree[idx<<1|1].add % mod + tree[idx].add) % mod; tree[idx<<1].mul = tree[idx<<1].mul % mod * tree[idx].mul % mod; tree[idx<<1|1].mul = tree[idx<<1|1].mul % mod * tree[idx].mul % mod; tree[idx<<1].sum = (tree[idx<<1].sum % mod * tree[idx].mul % mod + tree[idx<<1].size() * tree[idx].add % mod) % mod; tree[idx<<1|1].sum = (tree[idx<<1|1].sum % mod * tree[idx].mul % mod + tree[idx<<1|1].size() * tree[idx].add % mod) % mod; tree[idx].add = 0; tree[idx].mul = 1; } void build(int left, int right, int idx) { tree[idx].left = left; tree[idx].right = right; tree[idx].sum = 0; tree[idx].mul = 1; tree[idx].add = 0; if (left == right) { tree[idx].sum = value[left] % mod; return ; } int mid = tree[idx].mid(); build(left, mid, idx<<1); build(mid+1, right, idx<<1|1); pushUp(idx); } void update(int left, int right, int idx, int opt, long long val) { if (tree[idx].left == left && tree[idx].right == right) { if (opt == 1) { tree[idx].add = (tree[idx].add + val) % mod; tree[idx].sum = (tree[idx].sum + tree[idx].size() % mod * val) % mod; } else { tree[idx].add = tree[idx].add % mod * val % mod; tree[idx].mul = tree[idx].mul % mod * val % mod; tree[idx].sum = tree[idx].sum % mod * val % mod; } return ; } pushDown(idx); int mid = tree[idx].mid(); if (right <= mid) update(left, right, idx<<1, opt, val); else if (left > mid) update(left, right, idx<<1|1, opt, val); else { update(left, mid, idx<<1, opt, val); update(mid+1, right, idx<<1|1, opt, val); } pushUp(idx); } long long query(int left, int right, int idx) { if (tree[idx].left == left && tree[idx].right == right) { return tree[idx].sum % mod; } pushDown(idx); int mid = tree[idx].mid(); if (right <= mid) return query(left, right, idx<<1); else if (left > mid) return query(left, right, idx<<1|1); else { return (query(left, mid, idx<<1) % mod + query(mid+1, right, idx<<1|1)); } } }; SegmentTree tree; int n, m; void init() { scanf("%d %lld", &n, &mod); for (int i = 1; i <= n; i++) scanf("%lld", &value[i]); tree.build(1, n, 1); } void work() { scanf("%d", &m); for (int i = 1; i <= m; i++) { int opt, x, y; long long val; scanf("%d", &opt); if (opt != 3) { scanf("%d %d %lld", &x, &y, &val); tree.update(x, y, 1, 3-opt, val % mod); } else { scanf("%d %d", &x, &y); printf("%lld\n", tree.query(x, y, 1) % mod); } } } int main() { init(); work(); }
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <vector> using namespace std; const int maxn = 101000; long long value[maxn], mod; struct SegNode { int left, right; long long sum, add, mul; }; struct SegmentTree { SegNode tree[maxn*5]; void pushUp(int idx) { tree[idx].sum = tree[idx<<1].sum + tree[idx<<1|1].sum; } void pushDown(int idx, int left, int right) { long long add = tree[idx].add; long long mul = tree[idx].mul; tree[idx].sum = (tree[idx].sum % mod * tree[idx].mul % mod + (right - left + 1) * tree[idx].add % mod) % mod; tree[idx].add = 0; tree[idx].mul = 1; if (left == right) return ; tree[idx<<1].add = (mul % mod * tree[idx<<1].add % mod + add) % mod; tree[idx<<1|1].add = (mul % mod * tree[idx<<1|1].add % mod + add) % mod; tree[idx<<1].mul = tree[idx<<1].mul % mod * mul % mod; tree[idx<<1|1].mul = tree[idx<<1|1].mul % mod * mul % mod; } void build(int left, int right, int idx) { tree[idx].left = left; tree[idx].right = right; tree[idx].sum = 0; tree[idx].mul = 1; tree[idx].add = 0; if (left == right) { tree[idx].sum = value[left] % mod; return ; } int mid = (tree[idx].right + tree[idx].left) >> 1; build(left, mid, idx<<1); build(mid+1, right, idx<<1|1); pushUp(idx); } void update(int L, int R, int left, int right, int idx, int opt, long long value) { pushDown(idx, L, R); if (L >= left && R <= right) { if (opt == 1) { tree[idx].add = (tree[idx].add + value) % mod; } else { tree[idx].add = tree[idx].add % mod * value % mod; tree[idx].mul = tree[idx].mul % mod * value % mod; } return ; } int mid = (L + R) >> 1; if (left <= mid) update(L, mid, left, right, idx<<1, opt, value); if (right >= mid+1) update(mid+1, R, left, right, idx<<1|1, opt, 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) { return tree[idx].sum % mod; } int mid = (L + R) >> 1; long long ans = 0; if (left <= mid) ans = (ans + query(L, mid, left, right, idx<<1)) % mod; if (right >= mid + 1) ans = (ans + query(mid+1, R, left, right, idx<<1|1)) % mod; return ans; } }; SegmentTree tree; int n, m; void init() { scanf("%d %lld", &n, &mod); for (int i = 1; i <= n; i++) { scanf("%lld", &value[i]); } tree.build(1, n, 1); } void work() { scanf("%d", &m); for (int i = 1; i <= m; i++) { int opt, x, y; long long val; scanf("%d", &opt); if (opt != 3) { scanf("%d %d %lld", &x, &y, &val); tree.update(1, n, x, y, 1, 3-opt, val % mod); } else { scanf("%d %d", &x, &y); printf("%lld\n", tree.query(1, n, x, y, 1) % mod); } } } int main() { init(); work(); }
HDU 4578:http://acm.hdu.edu.cn/showproblem.php?pid=4578
这里还有道加强版,维护区间1次方和,2次方和,3次方和,区间加一个数,乘一个数,赋值。
更新的做法类似,要注意特殊处理赋值操作,赋值操作相当于a=1,b=0。
然后对于查询,其实2次方和,3次方和都可以展开来搞~
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std; const int maxn = 100100; const int mod = 10007; struct SegNode { int left, right; int sum1, sum2, sum3; int add, mul, set; int mid() { return (left + right) >> 1; } int 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) % mod; tree[idx].sum2 = (tree[idx<<1].sum2 + tree[idx<<1|1].sum2) % mod; tree[idx].sum3 = (tree[idx<<1].sum3 + tree[idx<<1|1].sum3) % mod; } void pushDown(int idx) { if (tree[idx].set != 0) { int set1 = tree[idx].set % mod; int set2 = set1 % mod * set1 % mod; int set3 = set2 % mod * set1 % mod; tree[idx<<1].set = set1; tree[idx<<1|1].set = set1; tree[idx<<1].add = 0; tree[idx<<1|1].add = 0; tree[idx<<1].mul = 1; tree[idx<<1|1].mul = 1; tree[idx<<1].sum1 = tree[idx<<1].size() * set1 % mod; tree[idx<<1|1].sum1 = tree[idx<<1|1].size() * set1 % mod; tree[idx<<1].sum2 = tree[idx<<1].size() * set2 % mod; tree[idx<<1|1].sum2 = tree[idx<<1|1].size() * set2 % mod; tree[idx<<1].sum3 = tree[idx<<1].size() * set3 % mod; tree[idx<<1|1].sum3 = tree[idx<<1|1].size() * set3 % mod; tree[idx].set = 0; } int mul1 = tree[idx].mul % mod; int mul2 = mul1 % mod * mul1 % mod; int mul3 = mul2 % mod * mul1 % mod; int add1 = tree[idx].add % mod; int add2 = add1 % mod * add1 % mod; int add3 = add2 % mod * add1 % mod; tree[idx<<1].add = (tree[idx].mul % mod * tree[idx<<1].add % mod + tree[idx].add) % mod; tree[idx<<1|1].add = (tree[idx].mul % mod * tree[idx<<1|1].add % mod + tree[idx].add) % mod; tree[idx<<1].mul = tree[idx<<1].mul % mod * tree[idx].mul % mod; tree[idx<<1|1].mul = tree[idx<<1|1].mul % mod * tree[idx].mul % mod; int sum1 = tree[idx<<1].sum1; int sum2 = tree[idx<<1].sum2; int sum3 = tree[idx<<1].sum3; int size = tree[idx<<1].size(); tree[idx<<1].sum1 = (sum1 % mod * mul1 % mod + size % mod * add1 % mod) % mod; tree[idx<<1].sum2 = (sum2 % mod * mul2 % mod + 2 * add1 % mod * mul1 % mod * sum1 % mod + size % mod * add2 % mod) % mod; tree[idx<<1].sum3 = (mul3%mod*sum3%mod + 3*mul2%mod*add1%mod*sum2%mod + 3*mul1%mod*add2%mod*sum1%mod + size%mod*add3%mod) % mod; sum1 = tree[idx<<1|1].sum1; sum2 = tree[idx<<1|1].sum2; sum3 = tree[idx<<1|1].sum3; size = tree[idx<<1|1].size(); tree[idx<<1|1].sum1 = (sum1 % mod * mul1 % mod + size % mod * add1 % mod) % mod; tree[idx<<1|1].sum2 = (sum2 % mod * mul2 % mod + 2 * add1 % mod * mul1 % mod * sum1 % mod + size % mod * add2 % mod) % mod; tree[idx<<1|1].sum3 = (mul3%mod*sum3%mod + 3*mul2%mod*add1%mod*sum2%mod + 3*mul1%mod*add2%mod*sum1%mod + size%mod*add3%mod) % mod; tree[idx].add = 0; tree[idx].mul = 1; } 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].set = 0; tree[idx].mul = 1; 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); pushUp(idx); } void update(int left, int right, int idx, int opt, int val) { if (tree[idx].left == left && tree[idx].right == right) { int val1 = val % mod; int val2 = val1 % mod * val1 % mod; int val3 = val2 % mod * val1 % mod; int sum1 = tree[idx].sum1; int sum2 = tree[idx].sum2; int sum3 = tree[idx].sum3; int size = tree[idx].size(); if (opt == 1) { tree[idx].add = (tree[idx].add + val1 % mod) % mod; tree[idx].sum1 = (sum1 + size * val1 % mod) % mod; tree[idx].sum2 = (sum2 + 2 * sum1 % mod * val1 % mod + size % mod * val2 % mod) % mod; tree[idx].sum3 = (sum3 + 3 * sum2 % mod * val1 % mod + 3 * sum1 % mod * val2 % mod + size % mod * val3 % mod) % mod; } else if (opt == 2) { tree[idx].add = tree[idx].add * val1 % mod; tree[idx].mul = tree[idx].mul * val1 % mod; tree[idx].sum1 = sum1 % mod * val1 % mod; tree[idx].sum2 = sum2 % mod * val2 % mod; tree[idx].sum3 = sum3 % mod * val3 % mod; } else { tree[idx].add = 0; tree[idx].mul = 1; tree[idx].set = val1; tree[idx].sum1 = size % mod * val1 % mod; tree[idx].sum2 = size % mod * val2 % mod; tree[idx].sum3 = size % mod * val3 % mod; } return ; } pushDown(idx); int mid = tree[idx].mid(); if (right <= mid) update(left, right, idx<<1, opt, val); else if (left > mid) update(left, right, idx<<1|1, opt, val); else { update(left, mid, idx<<1, opt, val); update(mid+1, right, idx<<1|1, opt, val); } pushUp(idx); } int query(int left, int right, int idx, int opt) { if (tree[idx].left == left && tree[idx].right == right) { if (opt == 1) return tree[idx].sum1; else if (opt == 2) return tree[idx].sum2; else return tree[idx].sum3; } pushDown(idx); int mid = tree[idx].mid(); if (right <= mid) return query(left, right, idx<<1, opt); else if (left > mid) return query(left, right, idx<<1|1, opt); else { return (query(left, mid, idx<<1, opt) % mod + query(mid+1, right, idx<<1|1, opt)) % mod; } } }; SegmentTree tree; int N, M; void work() { tree.build(1, N, 1); int x, y, val, opt; for (int i = 0; i < M; i++) { scanf("%d %d %d %d", &opt, &x, &y, &val); if (opt == 4) printf("%d\n", tree.query(x, y, 1, val)); else tree.update(x, y, 1, opt, val); } } int main() { while (scanf("%d %d", &N, &M) != EOF) { if (N == 0 && M == 0) break; work(); } }
线段树水题集锦
SPOJ GSS1 && SPOJ GSS3
链接:http://www.spoj.com/problems/GSS1/ http://www.spoj.com/problems/GSS3/
题意:GSS1和GSS3一样query都是区间最大连续和,只不过GSS3有个单点update罢了
做法:维护sum(区间和),maxSum(区间最大连续和),maxLeft(左儿子区间最大连续和),maxRight(右儿子区间最大连续和)
代码君:GSS1:http://ideone.com/5tepgk GSS3:http://ideone.com/MsopAu
SPOJ FREQUENT
链接:http://www.spoj.com/problems/FREQUENT/
题意:给个不下降序列,无update,query是求区间重复出现最多的数
做法:注意到是不下降序列,那么这个问题就转化成求区间连续相同序列的长度,因为是不下降的,所以不用维护区间最左和最右的值,可以只维护maxLen,leftLen,rightLen。
SPOJ