[BZOJ2388]旅行规划
Posted xjr_01
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ2388]旅行规划相关的知识,希望对你有一定的参考价值。
[BZOJ2388]旅行规划
试题描述
输入
输出
输入示例
5 1 8 -8 3 -7 3 1 1 5 0 1 3 6 1 2 4
输出示例
9 22
数据规模及约定
对于20%的数据,n,m≤3000;
对于40%的数据,n,m≤30000;
对于50%的数据,n,m≤50000;
另外20%的数据,n,m≤100000,修改操作≤20;
对于100%的数据,n,m≤100000。
题解
这题就是让维护区间最大前缀和(前缀和左端点为 1)。那么我们不妨就维护这个前缀和。
那么区间 [l, r] 的修改操作就变成了从第 l 个数开始,依次给每个位置加上 k, 2k, 3k, ... , (r-l+1)k。
查询操作就是询问区间最大值。
我们对序列分块。考虑修改操作,对于整块的我们打两个懒标记:addv[i] 表示这一块中的所有数增加 addv[i] 的值;K[i] 表示这一块中增加的等差数列的公差,即这一块中的元素在加完 addv[i] 后依次要加上 K[i], 2K[i], 3K[i], ... , siz · K[i]。再想想询问如何处理,对于整块的询问相当于就是找到 max{ S[x] + addv[i] + (x - st[i] + 1)K[i] | st[i] ≤ x ≤ en[i] }(st[i] 和 en[i] 表示第 i 个块的起始和终点位置),我们发现如果把 (x - st[i] + 1, S[x]) 当作坐标系上的点,那么询问就相当于用一条斜率为 -K[i] 的直线去碰那个点,要求找到最大的截距,解决这个问题维护凸包即可。
注意当 K[i] 和 addv[i] 变化时(即整块都被修改),不需要重新维护凸包形态(想一想,为什么)。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cctype> #include <algorithm> #include <cmath> using namespace std; const int BufferSize = 1 << 16; char buffer[BufferSize], *Head, *Tail; inline char Getchar() { if(Head == Tail) { int l = fread(buffer, 1, BufferSize, stdin); Tail = (Head = buffer) + l; } return *Head++; } int read() { int x = 0, f = 1; char c = Getchar(); while(!isdigit(c)){ if(c == ‘-‘) f = -1; c = Getchar(); } while(isdigit(c)){ x = x * 10 + c - ‘0‘; c = Getchar(); } return x * f; } #define maxn 100010 #define maxbl 320 #define oo (1ll << 60) #define LL long long int n, cb, st[maxbl], en[maxbl], blid[maxn]; LL Sa[maxn], addv[maxbl], K[maxbl], cp[maxbl]; struct Vec { LL x, y; Vec() {} Vec(LL _, LL __): x(_), y(__) {} Vec operator + (const Vec& t) const { return Vec(x + t.x, y + t.y); } Vec operator - (const Vec& t) const { return Vec(x - t.x, y - t.y); } LL operator ^ (const Vec& t) const { return x * t.y - y * t.x; } } poly[maxbl][maxbl]; void pushdown(int bl) { for(int i = st[bl]; i <= en[bl]; i++) Sa[i] += addv[bl] + K[bl] * (i - st[bl] + 1); addv[bl] = K[bl] = 0; return ; } void build_poly(int bl) { cp[bl] = 0; for(int i = st[bl]; i <= en[bl]; i++) { while(cp[bl] > 1 && (poly[bl][cp[bl]] - poly[bl][cp[bl]-1] ^ Vec(i - st[bl] + 1, Sa[i]) - poly[bl][cp[bl]]) >= 0) cp[bl]--; poly[bl][++cp[bl]] = Vec(i - st[bl] + 1, Sa[i]); } return ; } void update(int ql, int qr, int k) { if(blid[ql] == blid[qr]) { int b = blid[ql]; pushdown(b); for(int i = ql; i <= qr; i++) Sa[i] += (LL)k * (i - ql + 1); for(int i = qr + 1; i <= en[b]; i++) Sa[i] += (LL)k * (qr - ql + 1); build_poly(b); } else { int b = blid[ql]; pushdown(b); for(int i = ql; i <= en[b]; i++) Sa[i] += (LL)k * (i - ql + 1); build_poly(b); b = blid[qr]; pushdown(b); for(int i = st[b]; i <= qr; i++) Sa[i] += (LL)k * (i - ql + 1); for(int i = qr + 1; i <= en[b]; i++) Sa[i] += (LL)k * (qr - ql + 1); build_poly(b); for(int i = blid[ql] + 1; i <= blid[qr] - 1; i++) { addv[i] += (LL)k * (st[i] - ql); K[i] += k; } } for(int i = blid[qr] + 1; i <= cb; i++) addv[i] += (LL)k * (qr - ql + 1); return ; } LL getans(int bl, int p) { if(p > cp[bl]) return -oo; return poly[bl][p].x * K[bl] + poly[bl][p].y + addv[bl]; } LL query(int ql, int qr) { LL ans = -oo; if(blid[ql] == blid[qr]) { int b = blid[ql]; pushdown(b); build_poly(b); for(int i = ql; i <= qr; i++) ans = max(ans, Sa[i]); return ans; } int b = blid[ql]; pushdown(b); build_poly(b); for(int i = ql; i <= en[b]; i++) ans = max(ans, Sa[i]); b = blid[qr]; pushdown(b); build_poly(b); for(int i = st[b]; i <= qr; i++) ans = max(ans, Sa[i]); for(int i = blid[ql] + 1; i <= blid[qr] - 1; i++) { int l = 1, r = cp[i]; while(l < r) { int mid = l + r >> 1; if(getans(i, mid) <= getans(i, mid + 1)) l = mid + 1; else r = mid; } ans = max(ans, getans(i, l)); } return ans; } int main() { n = read(); for(int i = 1; i <= n; i++) Sa[i] = Sa[i-1] + read(); int m = sqrt(n + .5); for(int i = 1; i <= n; i++) { int bl = (i - 1) / m + 1; cb = max(cb, bl); blid[i] = bl; if(!st[bl]) st[bl] = i; en[bl] = i; } for(int i = 1; i <= cb; i++) build_poly(i); int q = read(); while(q--) { int tp = read(); if(!tp) { int ql = read(), qr = read(), k = read(); update(ql, qr, k); } else { int ql = read(), qr = read(); printf("%lld\n", query(ql, qr)); } } return 0; }
分块打起来好爽 ^_^
以上是关于[BZOJ2388]旅行规划的主要内容,如果未能解决你的问题,请参考以下文章
bzoj1690:[Usaco2007 Dec]奶牛的旅行 (分数规划 && 二分 && spfa)
bzoj1690[Usaco2007 Dec]奶牛的旅行 分数规划+Spfa
bzoj 1690: [Usaco2007 Dec]奶牛的旅行——分数规划+spfa判负环