spoj 1716 Can you answer these queries III(线段树)

和I相比有了单点更新,所以不能只记录一个前缀和,而是要在线段树上多维护一个sum,表示这个结点的区间和,然后其他的就和I一样了。

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;

const int N = 50001;
int a[N];

struct Node
{
int l, r, sum;
int maxl, maxr, maxn;
} node[N << 2];

void pushup( int i )
{
int lc = i << 1, rc = lc | 1;
node[i].sum = node[lc].sum + node[rc].sum;
node[i].maxl = max( node[lc].maxl, node[lc].sum + node[rc].maxl );
node[i].maxr = max( node[rc].maxr, node[rc].sum + node[lc].maxr );
node[i].maxn = max( node[lc].maxn, node[rc].maxn );
node[i].maxn = max( node[i].maxn, node[lc].maxr + node[rc].maxl );
}

void build( int i, int l, int r )
{
node[i].l = l, node[i].r = r;
if ( l == r )
{
node[i].sum = node[i].maxl = node[i].maxr = node[i].maxn = a[l];
return ;
}
int lc = i << 1, rc = lc | 1, mid = ( l + r ) >> 1;
build( lc, l, mid );
build( rc, mid + 1, r );
pushup(i);
}

void update( int i, int pos, int val )
{
if ( node[i].l == pos && node[i].r == pos )
{
node[i].sum = node[i].maxl = node[i].maxr = node[i].maxn = val;
return ;
}
int mid = ( node[i].l + node[i].r ) >> 1;
if ( pos <= mid )
{
update( i << 1, pos, val );
}
else
{
update( i << 1 | 1, pos, val );
}
pushup(i);
}

Node query( int i, int l, int r )
{
if ( node[i].l == l && node[i].r == r )
{
return node[i];
}
int lc = i << 1, rc = lc | 1, mid = ( node[i].l + node[i].r ) >> 1;
if ( r <= mid )
{
return query( lc, l, r );
}
else if ( l > mid )
{
return query( rc, l, r );
}
else
{
Node ln = query( lc, l, mid ), rn = query( rc, mid + 1, r ), res;
res.sum = ln.sum + rn.sum;
res.maxl = max( ln.maxl, ln.sum + rn.maxl );
res.maxr = max( rn.maxr, rn.sum + ln.maxr );
res.maxn = max( ln.maxn, rn.maxn );
res.maxn = max( res.maxn, ln.maxr + rn.maxl );
return res;
}
}

int main ()
{
int n, m;
while ( scanf("%d", &n) != EOF )
{
for ( int i = 1; i <= n; i++ )
{
scanf("%d", a + i);
}
build( 1, 1, n );
scanf("%d", &m);
while ( m-- )
{
int op, x, y;
scanf("%d%d%d", &op, &x, &y);
if ( op == 0 )
{
update( 1, x, y );
}
else
{
Node tmp = query( 1, x, y );
printf("%d\n", tmp.maxn);
}
}
}
return 0;
}

时间: 2024-10-21 21:48:26

spoj 1716 Can you answer these queries III(线段树)的相关文章

Spoj 1716 Can you answer these queries III 线段树 单点修改 区间求最大子段和

题目链接:点击打开链接 == 原来写1的时候已经把更新函数写好了.. #include <cstdio> #include <iostream> #include <algorithm> #include <string.h> #include <math.h> #include <vector> #include <map> using namespace std; #define N 50050 #define Lso

SPOJ GSS3 Can you answer these queries III (线段树)

题目大意: 求区间最大子区间的和. 思路分析: 记录左最大,右最大,区间最大. 注意Q_L  和 Q_R  就好. #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #define lson num<<1,s,mid #define rson num<<1|1,mid+1,e #define maxn 55555 using na

SPOJ GSS3 Can you answer these queries III ——线段树

[题目分析] GSS1的基础上增加修改操作. 同理线段树即可,多写一个函数就好了. [代码] #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <map> #include <set> #include <queue> #include <string> #include <iostream&

SPOJ GSS4 Can you answer these queries IV (线段树)

题目大意: 给出N个数 0     操作   把 l -----  r之间的数全部开平方 1     操作  输出 l -----r  之间的和 思路分析: 判断区间里的数字是否全相同.如果相同, 将cov 置为该数 查询的时候和更新的时候,如果碰到cov != -1 的  就直接返回就可以了 #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #incl

bzoj 2482: [Spoj GSS2] Can you answer these queries II 线段树

2482: [Spoj1557] Can you answer these queries II Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 145  Solved: 76[Submit][Status][Discuss] Description 给定n个元素的序列. 给出m个询问:求l[i]~r[i]的最大子段和(可选空子段). 这个最大子段和有点特殊:一个数字在一段中出现了两次只算一次. 比如:1,2,3,2,2,2出现了3次,但只算一次,

SPOJ 1557. Can you answer these queries II 线段树

Can you answer these queries II Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 https://www.spoj.com/problems/GSS2/ Description Being a completist and a simplist, kid Yang Zhe cannot solve but get Wrong Answer from most of the OI problems. And he refuse

SP1716 GSS3 - Can you answer these queries III 线段树

题目传送门:SP1043 GSS1 - Can you answer these queries I 更好的阅读体验 动态维护子段和最大值 前置知识 静态维护子段和最大值:SP1043 GSS1 - Can you answer these queries I 题解传送 题解: 提供结构体指针线段树写法: 设\(l\)为区间左端点, \(r\)为区间右端点: \(ls\)为以\(l\)为左端点的最大子段和, \(rs\)为以\(r\)为右端点的最大子段和; \(sum\)为区间和, \(val\

SPOJ GSS5 Can you answer these queries V ——线段树

[题目分析] GSS1上增加区间左右端点的限制. 直接分类讨论就好了. [代码] #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <map> #include <set> #include <queue> #include <string> #include <iostream> #i

Spoj 2916 Can you answer these queries V 线段树 求任意重叠区间的最大子段和

题目链接:点击打开链接 题意: T个测试数据 n个数字 q个询问 每个询问 : [x1, y1] [x2, y2] 问: int ans = -inf; for(int i = x1; i <= y1; i++) for(int j = max(x2, i); j <= y2; j++) ans = max(ans, query(i, j)); 思路: query_L(int l, int r) 求的是在区间[l,r]内 ,左端点为l的最大子段和. 其他和GSS3差不多. 分类讨论一下给定的区