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< ...
随机推荐
- 实习日记)select option 选择不同的option时, 页面发生不同的变化
怎么在下拉框的选择不同的option时, 页面发生响应的变化 因为option是没有点击事件什么的, 只有select才有, 所以不能通过option的点击事件来完成, 所以开始的尝试都失败了(之前 ...
- 移动端,多屏幕尺寸高清屏retina屏适配的解决方案
移动端高清.多屏适配方案 背景 开发移动端H5页面 面对不同分辨率的手机 面对不同屏幕尺寸的手机 视觉稿 在前端开发之前,视觉MM会给我们一个psd文件,称之为视觉稿. 对于移动端开发而言,为了做到页 ...
- python中的and和or(转载)
python中的and和or 4.6. and 和 or 的特殊性质在Python 中,and 和 or 执行布尔逻辑演算,如你所期待的一样,但是它们并不返回布尔值:而是,返回它们实际进行比较的值之一 ...
- EasyRTMP内置进入摄像机中实现网络推流直播摄像机的功能
本文转自博客:http://blog.csdn.net/jinlong0603/article/details/57468084 在前面的<如何用传统摄像机实现直接对接平台,类似于海康萤石.大华 ...
- Redisson实现Redis分布式锁的N种姿势(转)
Redis几种架构 Redis发展到现在,几种常见的部署架构有: 单机模式: 主从模式: 哨兵模式: 集群模式: 我们首先基于这些架构讲解Redisson普通分布式锁实现,需要注意的是,只有充分了解普 ...
- 配置tomcat,实现域名访问项目
首先,配置tomcat端口号为80,配置方法:配置tomcat,访问端口改为80 然后,配置访问项目时候,不用项目名,配置方法:配置tomcat,使访问项目时候无项目名 最后,配置tomcat的ser ...
- Objectvice-C中的super
/** 狗:哈士奇 */ //僵尸 #import <Foundation/Foundation.h> @interface Dog : NSObject - (void) walk; + ...
- performSelector: 与 dispatch_time 异同
iOS中timer相关的延时调用,常见的有NSObject中的performSelector:withObject:afterDelay:这个方法在调用的时候会设置当前runloop中timer,还有 ...
- Vue数据双向绑定探究
前面的啰嗦话,写一点吧,或许就有点用呢 使用过vue的小伙伴都会感觉,哇,这个框架对开发者这么友好,简直都要笑出声了. 确实,使用过vue的框架做开发的人都会感觉到,以前写一大堆操作dom,bom的东 ...
- android SDK中添加自定义api【转】
本文转载自:http://blog.csdn.net/a624731186/article/details/23548409 本文的思路: android APP调用自定义java API,自定义ja ...