POJ 2750 Potted Flower(线段树 + DP)
2015-08-10 21:47
295 查看
题目链接:http://poj.org/problem?id=2750
题意:给出N个数成环,再给M个操作,每次操作会改变某个数的数值,问每次更新完成后区间的最大和是多少,该区间不能是整个区间
思路:将环从某点切开看成一段序列,对于一个区间而言,如过所选序列不包括断点,那么直接求区间最大连续和smax即可,如果包括断点,那么答案则为max(smax, sum - smin),sum为区间总和,smin为区间最小连续和。
对于更新可以用线段树维护以下信息,sum为区间和,lmax为区间从左至右最大连续和,rmax为区间从右至左最大连续和,smax为区间最大连续和(最小连续和也同样处理)
故而有转移:
tr[rt].lmax = max(tr[ls].lmax, tr[ls].sum + tr[rs].lmax);
tr[rt].rmax = max(tr[rs].rmax, tr[rs].sum + tr[ls].rmax);
tr[rt].smax = max(max(tr[ls].smax, tr[rs].smax), tr[ls].rmax + tr[rs].lmax);
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <utility>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#include <climits>
#include <functional>
#include <deque>
#include <ctime>
#define ls rt << 1
#define rs rt << 1 | 1
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int maxn = 100010;
struct segtree
{
int sum;
int lmax, rmax, smax;
int lmin, rmin, smin;
} tr[maxn << 2];
void pushup(int rt)
{
tr[rt].sum = tr[ls].sum + tr[rs].sum;
tr[rt].lmax = max(tr[ls].lmax, tr[ls].sum + tr[rs].lmax);
tr[rt].rmax = max(tr[rs].rmax, tr[rs].sum + tr[ls].rmax);
tr[rt].smax = max(max(tr[ls].smax, tr[rs].smax), tr[ls].rmax + tr[rs].lmax);
tr[rt].lmin = min(tr[ls].lmin, tr[ls].sum + tr[rs].lmin);
tr[rt].rmin = min(tr[rs].rmin, tr[rs].sum + tr[ls].rmin);
tr[rt].smin = min(min(tr[ls].smin, tr[rs].smin), tr[ls].rmin + tr[rs].lmin);
}
void build(int l, int r, int rt)
{
if (l == r)
{
scanf("%d", &tr[rt].sum);
tr[rt].lmax = tr[rt].rmax = tr[rt].smax = tr[rt].sum;
tr[rt].lmin = tr[rt].rmin = tr[rt].smin = tr[rt].sum;
return ;
}
int mid = (l + r) >> 1;
build(lson);
build(rson);
pushup(rt);
}
void update(int p, int c, int l, int r, int rt)
{
if (l == r)
{
tr[rt].sum = c;
tr[rt].lmax = tr[rt].rmax = tr[rt].smax = c;
tr[rt].lmin = tr[rt].rmin = tr[rt].smin = c;
return ;
}
int mid = (l + r) >> 1;
if (p <= mid)
update(p, c, lson);
else
update(p, c, rson);
pushup(rt);
}
int main()
{
int n;
while (~scanf("%d", &n))
{
build(1, n, 1);
int m;
scanf("%d", &m);
while (m--)
{
int p, c;
scanf("%d%d", &p, &c);
update(p, c, 1, n, 1);
if (tr[1].sum == tr[1].smax)
printf("%d\n", tr[1].sum - tr[1].smin);
else
printf("%d\n", max(tr[1].smax, tr[1].sum - tr[1].smin));
}
}
return 0;
}
题意:给出N个数成环,再给M个操作,每次操作会改变某个数的数值,问每次更新完成后区间的最大和是多少,该区间不能是整个区间
思路:将环从某点切开看成一段序列,对于一个区间而言,如过所选序列不包括断点,那么直接求区间最大连续和smax即可,如果包括断点,那么答案则为max(smax, sum - smin),sum为区间总和,smin为区间最小连续和。
对于更新可以用线段树维护以下信息,sum为区间和,lmax为区间从左至右最大连续和,rmax为区间从右至左最大连续和,smax为区间最大连续和(最小连续和也同样处理)
故而有转移:
tr[rt].lmax = max(tr[ls].lmax, tr[ls].sum + tr[rs].lmax);
tr[rt].rmax = max(tr[rs].rmax, tr[rs].sum + tr[ls].rmax);
tr[rt].smax = max(max(tr[ls].smax, tr[rs].smax), tr[ls].rmax + tr[rs].lmax);
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <utility>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#include <climits>
#include <functional>
#include <deque>
#include <ctime>
#define ls rt << 1
#define rs rt << 1 | 1
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int maxn = 100010;
struct segtree
{
int sum;
int lmax, rmax, smax;
int lmin, rmin, smin;
} tr[maxn << 2];
void pushup(int rt)
{
tr[rt].sum = tr[ls].sum + tr[rs].sum;
tr[rt].lmax = max(tr[ls].lmax, tr[ls].sum + tr[rs].lmax);
tr[rt].rmax = max(tr[rs].rmax, tr[rs].sum + tr[ls].rmax);
tr[rt].smax = max(max(tr[ls].smax, tr[rs].smax), tr[ls].rmax + tr[rs].lmax);
tr[rt].lmin = min(tr[ls].lmin, tr[ls].sum + tr[rs].lmin);
tr[rt].rmin = min(tr[rs].rmin, tr[rs].sum + tr[ls].rmin);
tr[rt].smin = min(min(tr[ls].smin, tr[rs].smin), tr[ls].rmin + tr[rs].lmin);
}
void build(int l, int r, int rt)
{
if (l == r)
{
scanf("%d", &tr[rt].sum);
tr[rt].lmax = tr[rt].rmax = tr[rt].smax = tr[rt].sum;
tr[rt].lmin = tr[rt].rmin = tr[rt].smin = tr[rt].sum;
return ;
}
int mid = (l + r) >> 1;
build(lson);
build(rson);
pushup(rt);
}
void update(int p, int c, int l, int r, int rt)
{
if (l == r)
{
tr[rt].sum = c;
tr[rt].lmax = tr[rt].rmax = tr[rt].smax = c;
tr[rt].lmin = tr[rt].rmin = tr[rt].smin = c;
return ;
}
int mid = (l + r) >> 1;
if (p <= mid)
update(p, c, lson);
else
update(p, c, rson);
pushup(rt);
}
int main()
{
int n;
while (~scanf("%d", &n))
{
build(1, n, 1);
int m;
scanf("%d", &m);
while (m--)
{
int p, c;
scanf("%d%d", &p, &c);
update(p, c, 1, n, 1);
if (tr[1].sum == tr[1].smax)
printf("%d\n", tr[1].sum - tr[1].smin);
else
printf("%d\n", max(tr[1].smax, tr[1].sum - tr[1].smin));
}
}
return 0;
}
相关文章推荐
- 串讲Apache OFBiz技术架构
- 面试可能的知识点和坑
- Get Luffy Out (poj 2723 二分+2-SAT)
- copy mutablecopy 和 retain 的 区别
- Apache OFBiz源码解读之MVC模型
- HDU 4767( china + 矩阵快速幂)
- javascript trim函数在IE下不能用
- poj 3461 Oulipo 字符串匹配 KMP算法
- java下读取键盘输入的简单方法
- 谈Apache OFbiz 会员模块表结构设计
- 两道笔试编程题(求水仙数和求平方根数组之和)
- Linux C语言程序设计(十一)——Mac上编写与编译C文件
- 梦想在路上
- COJ 0346 WZJ的旅行(二)更新动态树分治版本
- 一步一步学习SignalR进行实时通信_2_Persistent Connections
- Spring面试问答
- poj 3723 Conscription(最大生成树)
- 老友记高清十季全
- 用过滤器过滤全站非法字符
- kmp(第二次个人赛)*(重复次数->长度最长)