首页 > 其他分享 >Luogu 6821 PA2012 Tanie linie

Luogu 6821 PA2012 Tanie linie

时间:2023-07-20 18:56:17浏览次数:41  
标签:llx 子段 int Luogu rhs PA2012 linie ans sum

这里只讲加强版,这是严格弱化。

结论是贪心。每次取出最大和连续子段,目前答案加上这个子段和,然后再把这个子段取反(相反数T),然后求整个过程答案的最大值。

考虑费用流模型。对于 \(i\le n\),\(S\to i\) 连边,\(i\to T\) 连边,流量为 \(1\) 费用为 \(0\);\(i\to i+1\) 连边,流量为 \(1\) 费用为 \(-a_i\)。求费用流的时候,取 \(S\to i\to j\to T\) 流,代表取了 \([i,j)\) 这个区间。不难发现上面贪心策略对应的就是费用流的贪心,所以这也叫模拟费用流。

所以只用维护 \(2\) 种操作:

  • 求出区间最大子段和以及其两个端点 \(l,r\)。
  • 支持区间取相反数。

考虑用线段树维护这个东西。

正常的区间最大子段和需要维护 \(lmx,rmx,mx\) 三个值嘛,分别表示取左端点的最大子段,取右端点的最大子段和整个区间的最大子段。由于要求端点位置,还需要维护 \(lx,rx,llx,rrx\) 表示取右端点的最大子段的左端点、取左端点最大子段的右端点、以及这个区间最大子段的左右端点。合并的时候简单讨论一下就可以了。

现在要区间取反,所以添加一个标记,把最大改成最小,再维护 \(lmn,rmn,mn,ln,rn,lln,rrn\) 七个值即可,也是简单讨论一下。

然后询问之间互相独立,要开个栈存下所有取反操作,逐一还原回去。

复杂度 \(O(qk\log n)\),这是加强版的代码。

#include <bits/stdc++.h>
using namespace std;

namespace vbzIO {
	char ibuf[(1 << 20) + 1], *iS, *iT;
	#if ONLINE_JUDGE
	#define gh() (iS == iT ? iT = (iS = ibuf) + fread(ibuf, 1, (1 << 20) + 1, stdin), (iS == iT ? EOF : *iS++) : *iS++)
	#else
	#define gh() getchar()
	#endif
	#define rd read
	#define wr write
	#define pc putchar
	#define pi pair<int, int>
	#define mp make_pair
	#define fi first
	#define se second
	#define pb push_back
	#define ins insert
	#define era erase
	inline int read () {
		char ch = gh();
		int x = 0;
		bool t = 0;
		while (ch < '0' || ch > '9') t |= ch == '-', ch = gh();
		while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch ^ 48), ch = gh();
		return t ? ~(x - 1) : x;
	}
	inline void write(int x) {
		if (x < 0) {
			x = ~(x - 1);
			putchar('-');
		}
		if (x > 9)
			write(x / 10);
		putchar(x % 10 + '0');
	}
}
using vbzIO::read;
using vbzIO::write;

const int N = 1e5 + 100;
bool chkmx(int &x, int y) { return x < y ? (x = y, 1) : 0; }
bool chkmn(int &x, int y) { return x > y ? (x = y, 1) : 0; }
struct seg {
	int sum;
	int lmx, rmx, mx, lx, rx, llx, rrx;
	int lmn, rmn, mn, ln, rn, lln, rrn;
	seg operator + (const seg &rhs) const {
		seg ans;
		ans.sum = sum + rhs.sum;
		
		ans.lmx = lmx, ans.llx = llx, ans.rmx = rhs.rmx, ans.rrx = rhs.rrx;
		if (chkmx(ans.lmx, sum + rhs.lmx)) ans.llx = rhs.llx;
		if (chkmx(ans.rmx, rhs.sum + rmx)) ans.rrx = rrx;
		ans.mx = mx, ans.lx = lx, ans.rx = rx;
		if (chkmx(ans.mx, rhs.mx)) ans.lx = rhs.lx, ans.rx = rhs.rx;
		if (chkmx(ans.mx, rmx + rhs.lmx)) ans.lx = rrx, ans.rx = rhs.llx;
		
		ans.lmn = lmn, ans.lln = lln, ans.rmn = rhs.rmn, ans.rrn = rhs.rrn;
		if (chkmn(ans.lmn, sum + rhs.lmn)) ans.lln = rhs.lln;
		if (chkmn(ans.rmn, rhs.sum + rmn)) ans.rrn = rrn;
		ans.mn = mn, ans.ln = ln, ans.rn = rn;
		if (chkmn(ans.mn, rhs.mn)) ans.ln = rhs.ln, ans.rn = rhs.rn;
		if (chkmn(ans.mn, rmn + rhs.lmn)) ans.ln = rrn, ans.rn = rhs.lln;
	
		return ans;
	}
} tr[N << 2];
int n, m, a[N], tag[N << 2];
stack<pi> opt;

void revt(seg &x) {
	seg ans;
	ans.sum = -x.sum;
	ans.lmx = -x.lmn, ans.llx = x.lln, ans.rmx = -x.rmn, ans.rrx = x.rrn;
	ans.lmn = -x.lmx, ans.lln = x.llx, ans.rmn = -x.rmx, ans.rrn = x.rrx;
	ans.mx = -x.mn, ans.lx = x.ln, ans.rx = x.rn;
	ans.mn = -x.mx, ans.ln = x.lx, ans.rn = x.rx;
	x = ans;
}

void sett(int l, int x) {
	tr[x] = (seg) {
		a[l], 
		a[l], a[l], a[l], l, l, l, l, 
		a[l], a[l], a[l], l, l, l, l
	};
}

#define ls x << 1
#define rs x << 1 | 1
#define mid ((l + r) >> 1)
void pushup(int x) { tr[x] = tr[ls] + tr[rs]; }
void pushrev(int x) { tag[x] ^= 1, revt(tr[x]); }
void pushdown(int x) {
	if (!tag[x]) return;
	pushrev(ls), pushrev(rs);
	tag[x] = 0;
}

void build(int l, int r, int x) {
	if (l == r) return sett(l, x);
	build(l, mid, ls), build(mid + 1, r, rs), pushup(x);
}

void upd(int l, int r, int p, int x) {
	if (l == r) return sett(l, x);
	pushdown(x);
	if (p <= mid) upd(l, mid, p, ls);
	else upd(mid + 1, r, p, rs);
	pushup(x);
}

void rev(int l, int r, int s, int t, int x) {
	if (s <= l && r <= t) return pushrev(x);
	pushdown(x);
	if (s <= mid) rev(l, mid, s, t, ls);
	if (t > mid) rev(mid + 1, r, s, t, rs);
	pushup(x);
}

seg qry(int l, int r, int s, int t, int x) {
	if (s <= l && r <= t) return tr[x];
	pushdown(x);
	if (s > mid) return qry(mid + 1, r, s, t, rs);
	else if (t <= mid) return qry(l, mid, s, t, ls);
	else return qry(l, mid, s, t, ls) + qry(mid + 1, r, s, t, rs);
}

int main() {
	n = rd();
	for (int i = 1; i <= n; i++) a[i] = rd();
	build(1, n, 1), m = rd();
	while (m--) {
		int op = rd(), l = rd(), r = rd();
		if (!op) a[l] = r, upd(1, n, l, 1);
		else {
			int k = rd(), ans = 0, sum = 0;
			while (k--) {
				seg tp = qry(1, n, l, r, 1);
				chkmx(ans, sum += tp.mx);
				opt.push(mp(tp.lx, tp.rx));
				rev(1, n, tp.lx, tp.rx, 1);
			}
			while (!opt.empty()) 
				rev(1, n, opt.top().fi, opt.top().se, 1), opt.pop();
			wr(ans), puts("");
		}
	}
	return 0;
} 

标签:llx,子段,int,Luogu,rhs,PA2012,linie,ans,sum
From: https://www.cnblogs.com/Ender32k/p/17569293.html

相关文章

  • Luogu 5296 生成树计数
    好像有道题是求生成树权值和的和的,考虑\(\sum\limits_{T}\sum\limits_{e\inE(T)}w_e\)咋做。每条边给一个边权\(v_e(x)=1+w_ex\),然后跑矩阵树:\[\text{ans}=[x]\sum\limits_{T}\prod\limits_{e\inE(T)}v_e(x)\]受到来自神秘力量的启示,我们考虑类似上面这样构造边权。考虑......
  • Luogu 3412 仓鼠找sugar II
    你也许说得对,但我是真看不懂第一篇题解那个答案式子……预处理是差不多的。设\(f_u\)表示从\(u\tofa(u)\)的期望步数,\(g_u\)为\(fa(u)\tou\)的期望步数,\(d_u\)为\(u\)的度数。那么显然有:\[f_u=\frac{1}{d_u}\left(1+\sum\limits_{v\inson(u)}(1+f_v+f_u)\right)......
  • 【题解】Luogu[P3360] 偷天换日
    solution开题显然是个树形dp,只不过在树形dp上又增加了背包问题。我们不妨将每个走廊看成一个点,把交叉口看成边(当然也可以把交叉口看成点,不过写起来麻烦一些),于是就转化为了一棵二叉树。我们设\(f_{i,j}\)表示以\(i\)为根的子树内,花费了不超过\(j\)时间,能拿到的最大价值......
  • 【题解】Luogu[P2607] [ZJOI2008] 骑士
    题目说给定\(n\)个点\(n\)个关系,也就是\(n\)条边,显然是基环树,又因为没有规定一定连通,于是我们可以将题目简化为给定一个基环树森林,点有点权,相邻的两个点不能同时选,问最大点权和。part1我们先考虑如果没有环,只是树,该怎么做。这一部分很简单,令\(f_{i,0/1}\)表示以\(i\)......
  • [刷题笔记] Luogu P1168 中位数
    ProblemDescription题目描述非常简洁,不作解释。Solution题目要求对前奇数项求中位数?朴素的做法是暴力,但是范围1e5显然T。这里主要介绍一种堆顶堆的做法。堆顶堆是什么呢?我们不妨开两个堆,一个大根堆一个小根堆。动态维护中位数,初始令前1位的中位数为\(a_i\),遍历数组,若遇到比中......
  • 洛谷 Luogu P1038 [NOIP2003 提高组] 神经网络
    这题看着很吓人实则很简单。求输出层,正着求很麻烦,因为知不道谁连向这个点,所以可以反向建边,反着求。拓扑+dfs,时间复杂度\(\text{O(n+m)}\)#include<iostream>#include<cstdio>#include<queue>#defineN105#defineM(N*N/2+114)structE{intv,w;......
  • luogu-modle
    P3383【模板】线性筛素数https://blog.csdn.net/huang_miao_xin/article/details/51331710首先看一个关于质数分布的规律:大于等于5的质数一定和6的倍数相邻。例如5和7,11和13,17和19等等;在6的倍数相邻两侧并不是一定就是质数。证明:令x≥1,将大于等于5的自然数可表示成:[6x-1......
  • luogu0_entry
    新手场和普及场前6关新手场顺序与分支P1422小玉家的电费控制输出精度:cout.xxx();待查询P1089津津的储蓄计划注意int和float相乘,输出格式用"%d"数字会面目全非P1909买铅笔INT_MAX存在<limits.h>里,不加.h也不行循环P1035级数求和我写了一个求和的函数Sn(in......
  • luogu1_dfsbfs
    普及练习场知识点汇总:DFS、BFS、☆杨辉三角P1118USACO06FEB数字三角形☆求解的个数用深搜,求最优解用广搜。DFSP1219八皇后弱智一样的我,还建立NxN的矩阵来模拟。结果呢,检查(check)时要遍历整个棋盘,最终导致只能过部分。根本不用二维矩阵。dfs(i),因为传进来的i是行号,......
  • luogu2_fenzhi_math
    知识点:快速幂高精负进制分治P1226【模板】快速幂||取余运算https://www.luogu.org/blog/costudy/base-2就看这一篇题解!!!然后下面备份一下代码:intquickPow(inta,intb){ intans=1;while(b){if(b&1)//b是奇数吗?(最后一位是1) ans*=a; a*=a;b>>=1......