P2096 最佳旅游线路

题意

给定 n,mn, m,以及一个二维矩阵 ai,ja_{i,j},设 gi=max(a1,i,a2,i,,an,i)g_i = \max{(a_{1,i}, a_{2,i}, \dots, a_{n,i})},其中 1im1 \le i \le m,求一个 l,r(1lrm)l, r( 1 \le l \le r \le m) 最大化 i=lrgi\sum_{i=l}^r g_i,输出最大的 i=lrgi\sum_{i=l}^r g_i

思路

明显就是先贪心,然后最大子段和。最大子段和考虑线段树维护。不要以为线段树不好打,但是线段树可以做到 O(n)O(n) 预处理,O(logn)O(\log n) 单点修改和询问。远比 O(n)O(n) 预处理 O(1)O(1) 修改,O(n)O(n) 的 DP 速度快,因为 logn\log n 其实很小,当 logn=30,n=230\log n = 30, n = 2^{30},可以看到线段树复杂度均匀,多次询问修改是更好的选择。

代码:

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

const int N = 205, M = 20005;

int n, m, a[N][M], maxn[M];

struct Node
{
	int l, r;
	int sum, lmax, rmax, tmax;
	Node()
	{
		l = r = sum = 0;
		lmax = rmax = tmax = -1e9;
	}
	friend Node operator+(const Node& x, const Node& y)
	{
		Node p;
		p.sum = x.sum + y.sum;
		p.lmax = max(x.lmax, x.sum + y.lmax);
		p.rmax = max(y.rmax, y.sum + x.rmax);
		p.tmax = max({ x.tmax, y.tmax, x.rmax + y.lmax });
		return p;
	}
};

Node tree[M << 2];

inline void push_up(int u)
{
	int tl = tree[u].l, tr = tree[u].r;
	tree[u] = tree[u << 1] + tree[u << 1 | 1];
	tree[u].l = tl, tree[u].r = tr;
}

inline void build(int u, int l, int r)
{
	tree[u].l = l, tree[u].r = r;
	if (l == r)
	{
		tree[u].lmax = tree[u].rmax = tree[u].sum = tree[u].tmax = maxn[r];
	}
	else
	{
		int mid = (l + r) >> 1;
		build(u << 1, l, mid);
		build(u << 1 | 1, mid + 1, r);
		push_up(u);
	}
}

inline void modify(int u, int x, int v)
{
	if (tree[u].l == x && tree[u].r == x)
	{
		tree[u].lmax = tree[u].rmax = tree[u].sum = tree[u].tmax = v;
	}
	else
	{
		int mid = (tree[u].l + tree[u].r) >> 1;
		if (x <= mid) modify(u << 1, x, v);
		else modify(u << 1 | 1, x, v);
		push_up(u);
	}
}

Node query(int u, int l, int r)
{
	if (tree[u].l >= l && tree[u].r <= r) return tree[u];
	int mid = (tree[u].l + tree[u].r) >> 1;
	Node x, y;
	if (l <= mid) x = query(u << 1, l, r);
	if (r > mid) y = query(u << 1 | 1, l, r);
	return x + y;
}

int main()
{
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++) scanf("%d", &a[i][j]);
	}
	for (int i = 1; i <= m; i++)
	{
		maxn[i] = -1e8;
		for (int j = 1; j <= n; j++) maxn[i] = max(maxn[i], a[j][i]);
	}
	build(1, 1, m);
	printf("%d\n", query(1, 1, m).tmax);
	return 0;
}
posted @   HappyBobb  阅读(5)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示