题目链接 GSS

$GSS1$

对于每个询问$l$, $r$,查询$a_{l}$, $a_{l+1}$, $a_{l+2}$, ..., $a_{r}$这个序列的最大字段和。

建立线段树,每个节点维护四个信息

$c$:当前区间的元素和

$lc$:当前区间左端点开始的最大子序列和

$rc$:当前区间右端点结束的最大子序列和

$ret$:当前区间的答案

于是我们建立线段树的时候预处理出每个节点的四个信息,查询的时候返回一个节点,这个节点的$ret$即为答案。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)
#define lson i << 1, L, mid
#define rson i << 1 | 1, mid + 1, R
#define ls i << 1
#define rs i << 1 | 1 typedef long long LL; const int N = 1e5 + 10; struct node{
int c, lc, rc, ret;
} t[N << 2]; int n, q, l, r; void pushup(int i){
t[i].c = t[ls].c + t[rs].c;
t[i].lc = max(t[ls].lc, t[ls].c + t[rs].lc);
t[i].rc = max(t[rs].rc, t[rs].c + t[ls].rc);
t[i].ret = max(max(t[ls].ret, t[rs].ret), t[ls].rc + t[rs].lc);
} void build(int i, int L, int R){
if (L == R){
scanf("%d", &t[i].ret);
t[i].c = t[i].lc = t[i].rc = t[i].ret;
return;
} int mid = (L + R) >> 1; build(lson);
build(rson);
pushup(i);
} node query(int i, int L, int R, int l, int r){
if (l == L && R == r) return t[i]; int mid = (L + R) >> 1; if (r <= mid) return query(lson, l, r);
if (l > mid) return query(rson, l, r); node ta = query(lson, l, mid);
node tb = query(rson, mid + 1, r); node ans;
ans.c = ta.c + tb.c;
ans.lc = max(ta.lc, ta.c + tb.lc);
ans.rc = max(tb.rc, tb.c + ta.rc);
ans.ret = max(max(ta.ret, tb.ret), ta.rc + tb.lc);
return ans;
} int main(){ while (~scanf("%d", &n)){
build(1, 1, n);
scanf("%d", &q);
while (q--){
scanf("%d%d", &l, &r);
node ans = query(1, 1, n, l, r);
printf("%d\n", ans.ret);
}
} return 0;
}

$GSS2$

$GSS1$的去重版

什么意思呢

询问的形式还是完全一样的,就是子序列的价值稍微变了一下。

$GSS1$中子序列的价值是该子序列的元素和,$GSS2$这里是该子序列出现过的元素的和

做法和$GSS1$完全不一样。

我们对询问离线。然后排序,按照右端点升序。

然后从左往右扫过去,每次加入$a_{i}$的时候, 先把$a_{i}$加进去。

接着我们对$last[a_{i}] + 1$到$i-1$这段区间都加上$a_{i}$,$last[x]$表示$x$上一次出现的位置,初值为$0$。

维护线段树的话我们需要四个信息。

$now$:当前这个时候区间的最大值

$mx$:历史区间的最大值

$h$:历史lazy标记(传给后代)的最大值

$add$:当前lazy标记(需传给后代)的值

然后查询一遍就可以了。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)
#define lson i << 1, L, mid
#define rson i << 1 | 1, mid + 1, R
#define ls i << 1
#define rs i << 1 | 1
#define MP make_pair
#define fi first
#define se second typedef long long LL; const int N = 1e5 + 10;
const int d = 1e5; int n, m, x, y;
int a[N], c[N << 1];
vector <pair <int, int> > v[N];
LL mx[N << 2], now[N << 2], add[N << 2], h[N << 2];
LL ans[N]; void pushup(int i){
mx[i] = max(mx[ls], mx[rs]);
now[i] = max(now[ls], now[rs]);
} void pushdown(int i){
h[ls] = max(h[ls], add[ls] + h[i]);
h[rs] = max(h[rs], add[rs] + h[i]); add[ls] += add[i];
add[rs] += add[i]; mx[ls] = max(mx[ls], now[ls] + h[i]);
mx[rs] = max(mx[rs], now[rs] + h[i]); now[ls] += add[i];
now[rs] += add[i]; add[i] = 0;
h[i] = -1e16;
} void update(int i, int L, int R, int x, int val){
if (L == R && L == x){
mx[i] = now[i] = val;
return;
} int mid = (L + R) >> 1;
pushdown(i);
if (x <= mid) update(lson, x, val);
else update(rson, x, val);
pushup(i);
} void Add(int i, int L, int R, int l, int r, int val){
if (l <= L && R <= r){
now[i] += val;
mx[i] = max(mx[i], now[i]);
add[i] += val;
h[i] = max(h[i], add[i]);
return ;
} int mid = (L + R) >> 1;
pushdown(i);
if (l <= mid) Add(lson, l, r, val);
if (r > mid) Add(rson, l, r, val);
pushup(i);
} LL query(int i, int L, int R, int l, int r){
if (l <= L && R <= r) return mx[i];
int mid = (L + R) >> 1;
LL ret = -1e16;
pushdown(i);
if (l <= mid) ret = max(ret, query(lson, l, r));
if (r > mid) ret = max(ret, query(rson, l, r));
pushup(i);
return ret;
} int main(){ scanf("%d", &n);
rep(i, 1, n) scanf("%d", a + i);
scanf("%d", &m); rep(i, 1, ((n << 2) - 1)) mx[i] = h[i] = now[i] = -1e16; rep(i, 1, m){
scanf("%d%d", &x, &y);
v[y].push_back(MP(x, i));
} rep(i, 1, n){
update(1, 1, n, i, a[i]);
if (c[a[i] + d] + 1 < i) Add(1, 1, n, c[a[i] + d] + 1, i - 1, a[i]);
c[a[i] + d] = i;
for (auto u : v[i]) ans[u.se] = query(1, 1, n, u.fi, i);
} rep(i, 1, m) printf("%lld\n", max(0ll, ans[i]));
return 0;
}

$GSS3$

$GSS1$加个单点更新,没了。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)
#define lson i << 1, L, mid
#define rson i << 1 | 1, mid + 1, R
#define ls i << 1
#define rs i << 1 | 1 typedef long long LL; const int N = 1e5 + 10; struct node{
int c, lc, rc, ret;
} t[N << 2]; int n, q, l, r;
int op, x, y; void pushup(int i){
t[i].c = t[ls].c + t[rs].c;
t[i].lc = max(t[ls].lc, t[ls].c + t[rs].lc);
t[i].rc = max(t[rs].rc, t[rs].c + t[ls].rc);
t[i].ret = max(max(t[ls].ret, t[rs].ret), t[ls].rc + t[rs].lc);
} void build(int i, int L, int R){
if (L == R){
scanf("%d", &t[i].ret);
t[i].c = t[i].lc = t[i].rc = t[i].ret;
return;
} int mid = (L + R) >> 1; build(lson);
build(rson);
pushup(i);
} void update(int i, int L, int R, int x, int val){
if (L == x && L == R){
t[i].c = t[i].lc = t[i].rc = t[i].ret = val;
return;
} int mid = (L + R) >> 1;
if (x <= mid) update(lson, x, val);
else update(rson, x, val);
pushup(i);
} node query(int i, int L, int R, int l, int r){
if (l == L && R == r) return t[i]; int mid = (L + R) >> 1; if (r <= mid) return query(lson, l, r);
if (l > mid) return query(rson, l, r); node ta = query(lson, l, mid);
node tb = query(rson, mid + 1, r); node ans;
ans.c = ta.c + tb.c;
ans.lc = max(ta.lc, ta.c + tb.lc);
ans.rc = max(tb.rc, tb.c + ta.rc);
ans.ret = max(max(ta.ret, tb.ret), ta.rc + tb.lc);
return ans;
} int main(){ scanf("%d", &n);
build(1, 1, n);
scanf("%d", &q);
while (q--){
scanf("%d", &op);
if (op == 1){
scanf("%d%d", &l, &r);
node ans = query(1, 1, n, l, r);
printf("%d\n", ans.ret);
} else{
scanf("%d%d", &x, &y);
update(1, 1, n, x, y);
}
} return 0;
}

$GSS4$

这题做法很暴力

对那些值已经全部是1的区间结点打上永久标记即可。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)
#define ls i << 1
#define rs i << 1 | 1
#define lson ls, L, mid
#define rson rs, mid + 1, R typedef long long LL; const int N = 1e5 + 10; LL s[N << 2];
int t[N << 2];
int n;
int q;
int ca = 0; inline void pushup(int i){
s[i] = s[ls] + s[rs];
t[i] = t[ls] & t[rs];
} void build(int i, int L, int R){
if (L == R){
scanf("%lld", s + i);
t[i] = s[i] <= 1;
return;
} int mid = (L + R) >> 1; build(lson);
build(rson);
pushup(i);
} void update(int i, int L, int R, int l, int r){
if (t[i]) return;
if (L == R){
s[i] = sqrt(s[i]);
t[i] = s[i] <= 1;
return;
} int mid = (L + R) >> 1;
if (l <= mid) update(lson, l, r);
if (r > mid) update(rson, l, r);
pushup(i);
} LL query(int i, int L, int R, int l, int r){
if (l <= L && R <= r) return s[i];
int mid = (L + R) >> 1;
LL ret = 0;
if (l <= mid) ret += query(lson, l, r);
if (r > mid) ret += query(rson, l, r);
return ret;
} int main(){ while (~scanf("%d", &n)){
printf("Case #%d:\n", ++ca);
build(1, 1, n);
scanf("%d", &q);
while (q--){
int op, x, y;
scanf("%d%d%d", &op, &x, &y);
if (x > y) swap(x, y);
if (op == 1) printf("%lld\n", query(1, 1, n, x, y));
else update(1, 1, n, x, y);
}
putchar(10);
}
return 0;
}

  

$GSS5$

分类讨论,注意细节就可以了。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)
#define lson i << 1, L, mid
#define rson i << 1 | 1, mid + 1, R
#define ls i << 1
#define rs i << 1 | 1 const int N = 1e5 + 10; struct node{
int c, lc, rc, ret;
} t[N << 2]; int T;
int n, q, l, r;
int a[N], s[N];
int ans; void pushup(int i){
t[i].c = t[ls].c + t[rs].c;
t[i].lc = max(t[ls].lc, t[ls].c + t[rs].lc);
t[i].rc = max(t[rs].rc, t[rs].c + t[ls].rc);
t[i].ret = max(max(t[ls].ret, t[rs].ret), t[ls].rc + t[rs].lc);
} void build(int i, int L, int R){
if (L == R){
t[i].ret = a[L];
t[i].c = t[i].lc = t[i].rc = t[i].ret;
return;
} int mid = (L + R) >> 1; build(lson);
build(rson);
pushup(i);
} node query(int i, int L, int R, int l, int r){
if (l == L && R == r) return t[i]; int mid = (L + R) >> 1; if (r <= mid) return query(lson, l, r);
if (l > mid) return query(rson, l, r); node ta = query(lson, l, mid);
node tb = query(rson, mid + 1, r); node ans;
ans.c = ta.c + tb.c;
ans.lc = max(ta.lc, ta.c + tb.lc);
ans.rc = max(tb.rc, tb.c + ta.rc);
ans.ret = max(max(ta.ret, tb.ret), ta.rc + tb.lc);
return ans;
} int main(){ scanf("%d", &T);
while (T--){
scanf("%d", &n);
rep(i, 1, n) scanf("%d", a + i);
rep(i, 1, n) s[i] = s[i - 1] + a[i];
build(1, 1, n);
scanf("%d", &q);
while (q--){
int x1, y1, x2, y2;
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
ans = 0;
if (x2 == y1){
ans = query(1, 1, n, x1, y1).rc + query(1, 1, n, x2, y2).lc - a[y1];
printf("%d\n", ans);
} else if (y1 < x2){
ans = s[x2 - 1] - s[y1];
ans += query(1, 1, n, x1, y1).rc + query(1, 1, n, x2, y2).lc;
printf("%d\n", ans);
} else{
ans = query(1, 1, n, x2, y1).ret;
ans = max(ans, s[y1 - 1] - s[x2] + query(1, 1, n, x1, x2).rc + query(1, 1, n, y1, y2).lc);
ans = max(ans, query(1, 1, n, x1, x2).rc + query(1, 1, n, x2, y1).lc - a[x2]);
ans = max(ans, query(1, 1, n, x2, y1).rc + query(1, 1, n, y1, y2).lc - a[y1]);
printf("%d\n", ans);
}
} } return 0;
}

  

SPOJ GSS系列(数据结构维护技巧入门)的更多相关文章

  1. 【SPOJ GSS】数据结构题选做

    SPOJ GSS1 题意:给一个序列以及一些询问,每个是问\([l,r]\)中最大连续子序列和是多少. 思路:这个问题是以下问题的基础. 我们考虑用线段树来解决这个问题. 首先我们来想想如果要求出最大 ...

  2. SPOJ GSS 系列

    来怒做GSS系列了: GSS1:https://www.luogu.org/problemnew/show/SP1043 这题就是维护一个 sum , mx , lmx , rmx,转移时用结构体就好 ...

  3. spoj GSS系列简要题解

    文章目录 GSS1 GSS2 GSS3 GSS4 GSS5 GSS6 GSS7 GSS8 传送门 这个GSSGSSGSS系列全部是跟子段有关的数据结构菜题. 于是来水一篇博客. GSS1 传送门 题意 ...

  4. SPOJ GSS系列

    众所周知的仅次于ynoi的毒瘤数据结构系列.(跟Qtree系列并列?) GSS1: 长度为 $n$ 的序列 $a$,$m$ 个询问,每次询问区间 $[l,r]$ 之间的最大子段和. $1\le n,m ...

  5. 数据结构与算法入门系列教程-C#

    数据结构与算法入门系列教程 (一)为啥要学习数据结构与算法 曾经我也以为自己很牛逼,工作中同事也觉得我还可以,领导也看得起我,啥啥啥都好,就这样过了几年,忽然发现自己学新东西没劲.时代都变了,而我还只 ...

  6. 一起学微软Power BI系列-官方文档-入门指南(3)Power BI建模

    我们前2篇文章:一起学微软Power BI系列-官方文档-入门指南(1)Power BI初步介绍 和一起学微软Power BI系列-官方文档-入门指南(2)获取源数据 中,我们介绍了官方入门文档与获取 ...

  7. 一起学微软Power BI系列-官方文档-入门指南(4)Power BI的可视化

    在前面的系列文章中,我们介绍了官方有关获取数据,以及建模的原始文档和基本介绍.今天继续给大家介绍官方文档中,有关可视化的内容.实际上获获取数据和建模更注重业务关系的处理,而可视化则关注对数据的解读.这 ...

  8. 一起学微软Power BI系列-官方文档-入门指南(5)探索数据奥秘

    我们几篇系列文章中,我们介绍了官方入门文档与获取数据等基本知识.今天继续给大家另外一个重点,探索数据奥秘.有了数据源,有了模型,下一步就是如何解析数据了.解析数据的过程需要很多综合技能,不仅仅是需要掌 ...

  9. ShoneSharp语言(S#)的设计和使用介绍系列(4)— 入门概述

    ShoneSharp语言(S#)的设计和使用介绍 系列(4)- 入门概述 作者:Shone 声明:原创文章欢迎转载,但请注明出处,https://www.cnblogs.com/ShoneSharp. ...

随机推荐

  1. php 关于金额的几种计算方式

    php 关于金额的几种计算方式 平常开始开发过程中,多多少少都会遇到点关于金额的计算,比如设置返利.提现手续费.折扣啊等等诸如此类的比例,然后再计算出之后的实际的费用. 下面,以折扣为例,来实现这类计 ...

  2. IDEA入门学习笔记1:资料收集

    IDEA2018软件下载 :https://mp.weixin.qq.com/s?__biz=MzIwMjE1MjMyMw==&mid=2650200056&idx=1&sn= ...

  3. JDK1.8 HashMap$TreeNode.balanceInsertion 红黑树平衡插入

    红黑树介绍 1.节点是红色或黑色. 2.根节点是黑色. 3.每个叶子节点都是黑色的空节点(NIL节点). 4 每个红色节点的两个子节点都是黑色.(从每个叶子到根的所有路径上不能有两个连续的红色节点) ...

  4. poj 3280 回文字符串问题 dp算法

    题意:给一个字符串,构成回文(空也是回文) 其中增删都需要代价.问:代价最少? 思路:把字符串s变空  dp[i][j]表示变成回文的最小代价 for(i=m-1;i>=0;--i)       ...

  5. hdu2604 递推转换矩阵快速幂

    刚开始还以为用位运算与或几下几个循环就搞定了,算着算着发现不行........ 还是一种固定的切题角度,我假设有长度为n,总的排列数位f(n),怎么算他呢?从后往前考虑,因为大多数情况,都是用前面的结 ...

  6. 求1+2+...+n 【微软面试100题 第十二题】

    题目要求: 要求不能使用乘除法,for/while/if/else/switch/case等关键字以及条件判断语句(A?B:C). 参考资料:剑指offer第46题 题目分析: 方法1:利用类的静态成 ...

  7. 初试webpack打包

    第一次接触webpack,学习了如何用webpack打包,记录一下过程. 1.在项目根目录安装webpack $ npm install webpack --save-dev 2.新建一个webpac ...

  8. # Linux 命令学习记录

    Linux 命令学习记录 取指定文件夹下的任意一个文件,并用vim打开 vi $(ls -l|grep "^-"|head -n 1|awk '{print $9}') 统计给定文 ...

  9. 一句话学Java——Java重载和重写

    概念:重载是指两个不同的函数有相同的名称,可以是在本类之中的函数之间的重载,也可以是子类和父类的函数之间的函数重载. 重写:只能是子类重写父类的函数.这是多态的基础. 重写的规则:     参数:重写 ...

  10. iOS启动动画效果实现

    原理 在window上加一个UIImageView它的图片和启动图的图片一样,然后再调整动画 运行展示 demo百度云连接:http://pan.baidu.com/s/1c0QcYu0 more:网 ...