Can you answer these queries II
题意:
给一长度为n的序列,有m组询问,每一组询问给出[l,r]询问区间内的最大去重连续子段和。
解法:
考虑一下简化后的问题:如果题目要求询问查询以$r$为右端点且$l$大于等于给定值的去重连续子段和,
那么我们显然可以预处理出$pre(i)$表示$i$位置出现的数字上一次出现的位置。
那么我们可以从小到大枚举$r$,
线段树维护$[i,r]$的去重子段和,区间加+维护最大值进而求出$[i,r]$的去重子段和的最大值。
现在考虑r小于等于给定值的做法,
注意到r是从1开始到n枚举的,进而保证了线段树里出现过的值都是$[l_i,r_i],r_i<=r$的去重子段和。
所以我们只要维护一下历史上线段树$i$位置出现过的历史最大值即可。
注意区间加的$add$标记不可以简单的合并,
因为我们要求的是历史上出现过的最大值,有可能$add 2, add -2$两个标记合并为$add 0$,进而错过最优答案。
对于一个点的$add$操作可以认为是一个$add$的序列,
我们要维护$add$序列中出现过的最大的前缀和,类比经典的处理方法最大子段和。
注意到线段树要维护4个标记:
历史最大值
当前最大值
当前$add$
$add$序列里的最大前缀和
总效率$O(nlogn)$
#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <algorithm> #define N 100010
#define l(x) ch[x][0]
#define r(x) ch[x][1]
#define LL long long
#define INF 0x3f3f3f3f using namespace std; struct node
{
int l,r,id;
}b[N]; int n,totn,m;
int a[N],pre[N],a0[N];
int ch[N<<][];
LL max_all[N<<],maxv[N<<];
LL add_all[N<<],addv[N<<];
LL ansv[N];
map<int,int> pos; bool cmp(node a,node b)
{
return a.r<b.r;
} void push(int x)
{
if(!addv[x] && !add_all[x]) return;
add_all[l(x)]=max(add_all[l(x)],addv[l(x)]+max(add_all[x],0LL));
max_all[l(x)]=max(max_all[l(x)],maxv[l(x)]-addv[l(x)]+max(add_all[l(x)],0LL));
addv[l(x)]+=addv[x];
maxv[l(x)]+=addv[x]; add_all[r(x)]=max(add_all[r(x)],addv[r(x)]+max(add_all[x],0LL));
max_all[r(x)]=max(max_all[r(x)],maxv[r(x)]-addv[r(x)]+max(add_all[r(x)],0LL));
addv[r(x)]+=addv[x];
maxv[r(x)]+=addv[x];
addv[x]=;
add_all[x]=;
} void update(int x)
{
maxv[x]=max(maxv[l(x)], maxv[r(x)]);
max_all[x]=max(max_all[x],max_all[l(x)]);
max_all[x]=max(max_all[x],max_all[r(x)]);
} LL ask(int x,int l,int r,int ql,int qr)
{
push(x);
if(ql<=l && r<=qr) return max_all[x];
int mid=(l+r)>>;
LL ans=;
if(ql<=mid) ans = max(ans, ask(l(x),l,mid,ql,qr));
if(mid<qr) ans = max(ans, ask(r(x),mid+,r,ql,qr));
update(x);
return ans;
} void add(int x,int l,int r,int ql,int qr,LL qv)
{
push(x);
if(ql<=l && r<=qr)
{
addv[x]=qv;
add_all[x]=max(qv,0LL);
maxv[x]+=qv;
max_all[x]=max(max_all[x],maxv[x]);
return;
}
int mid=(l+r)>>;
if(ql<=mid) add(l(x),l,mid,ql,qr,qv);
if(mid<qr) add(r(x),mid+,r,ql,qr,qv);
update(x);
} int build(int l,int r)
{
int x=++totn;
max_all[x]=maxv[x]=;
add_all[x]=;
addv[x]=;
if(l==r) return x;
int mid=(l+r)>>;
l(x)=build(l,mid);
r(x)=build(mid+,r);
return x;
} int main()
{
while(~scanf("%d",&n))
{
for(int i=;i<=n;i++) scanf("%d",&a[i]);
scanf("%d",&m);
for(int i=;i<=m;i++)
{
scanf("%d%d",&b[i].l,&b[i].r);
b[i].id=i;
}
sort(b+,b+m+,cmp);
totn=;
pos.clear();
for(int i=;i<=n;i++)
{
if(pos.count(a[i])) pre[i]=pos[a[i]];
else pre[i]=,a0[i]=a[i];
pos[a[i]]=i;
}
build(,n);
int j=;
for(int i=;i<=n;i++)
{
add(,,n,pre[i]+,i,a[i]);
while(j<=m && b[j].r==i)
{
ansv[b[j].id]=ask(,,n,b[j].l,b[j].r);
j++;
}
}
for(int i=;i<=m;i++)
printf("%lld\n",ansv[i]);
}
return ;
}
Can you answer these queries II的更多相关文章
- BZOJ2482: [Spoj1557] Can you answer these queries II
题解: 从没见过这么XXX的线段树啊... T_T 我们考虑离线做,按1-n一个一个插入,并且维护区间[ j,i](i为当前插入的数)j<i的最优值. 但这个最优值!!! 我们要保存历史的最优值 ...
- 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/pr ...
- 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 ...
- spoj gss2 : Can you answer these queries II 离线&&线段树
1557. Can you answer these queries II Problem code: GSS2 Being a completist and a simplist, kid Yang ...
- SPOJ GSS2 - Can you answer these queries II(线段树 区间修改+区间查询)(后缀和)
GSS2 - Can you answer these queries II #tree Being a completist and a simplist, kid Yang Zhe cannot ...
- 【BZOJ2482】[Spoj1557] Can you answer these queries II 线段树
[BZOJ2482][Spoj1557] Can you answer these queries II Description 给定n个元素的序列. 给出m个询问:求l[i]~r[i]的最大子段和( ...
- SPOJ GSS2 Can you answer these queries II
Time Limit: 1000MS Memory Limit: 1572864KB 64bit IO Format: %lld & %llu Description Being a ...
- GSS2-Can you answer these queries II
---恢复内容开始--- 这道题真的是非常恶心,看题解看了半天才弄懂,而且题解上说的相当简略. 此题大意是询问去掉重复元素的最大子区间和,没有修改操作. 没有修改操作,这样就可以离线处理了. 这道题有 ...
- SPOJ1557 GSS2 Can you answer these queries II 历史最值线段树
传送门 题意:给出一个长度为$N$的数列,$Q$次询问,每一次询问$[l,r]$之间的最大子段和,相同的数只计算一次.所有数字的绝对值$\leq 10^5$ GSS系列中不板子的大火题,单独拿出来写 ...
- 【SPOJ - GSS2】Can you answer these queries II(线段树)
区间连续不重复子段最大值,要维护历史的最大值和当前的最大值,打两个lazy,离线 #include<cstdio> #include<cstring> #include< ...
随机推荐
- Linaro/Yocto/Openwrt
http://en.wikipedia.org/wiki/Linaro Linaro From Wikipedia, the free encyclopedia This article ap ...
- Django-mysq数据库链接问题
Django链接MySQL数据库有可能会报no model named MySQLdb, 解决办法: 首先安装pymysql 然后进入到项目目录,找到__init__.py文件,在里面添加 impor ...
- 惊艳的cygwin——Windows下的Linux命令行环境的配置和使用
http://www.tuicool.com/articles/2MramqI 时间 2014-07-29 09:28:36 点滴之间 聚沙成金 原文 http://www.path8.net/t ...
- h5的复制功能
js+html5实现复制文字按钮 <div> <input type="text" name="guanfangaddress" id=&qu ...
- Python使用Mysql过程中一些错误
Python使用Mysql过程中一些错误 ssh登录远程服务器 ssh ubuntu@xxx.xxx.xx.xx 第一:ubuntu终端中登录Mysql mysql -uroot -p 然后输入密码即 ...
- RecyclerView的那点事儿
RecyclerView 控件简单介绍 ListView的升级版 LinearLayoutManager GridLayoutManager StaggeredGridLayoutManager 定制 ...
- IOS8 通知中心(Notification Center)新特性
本文转载至 http://blog.csdn.net/jinkaiouyang/article/details/30029441 ios手机apple通知中心notificationCenter ...
- mongodb的锁和高并发
1 mongodb的锁 mongodb使用的读写锁. 2 mongodb高并发 同样是读写锁造成的问题. 3 findandmodify 该操作是原子的.
- Red Black Tree java.util.TreeSet
https://docs.oracle.com/javase/9/docs/api/java/util/SortedMap.html public interface SortedMap<K,V ...
- NOIP2015_提高组Day2_3_运输计划
这题思路很简单: 先对每个询问求距离,对距离由大到小排序, 二分最小距离,验证是否可行,验证时用差分处理: #include<iostream> #include<cstring&g ...