快来踩爆这个蒟蒻吧|

Little_corn

园龄:1年1个月粉丝:11关注:17

2024-04-25 13:19阅读: 10评论: 0推荐: 0

SP1557 GSS2 - Can you answer these queries II

link

题目大意:

给一个 n 个元素的序列,q 次询问 [li,ri] 的最大子段和(相同元素只算一个)。

n,q105,105ai105.

解法:

首先考虑最大子段和的经典动态解法:维护 prei,sufi,sumi,mxsumi 。这个时候你会发现无法合并。

Tips:对于区间询问问题,在没有思路时将其离线是一个很好的选择。

考虑离线问题并按右端点为第一关键字,右端点为第二关键字排序。用一个指针在数组中从左到右滑动,并同时加入滑动到的新点

那么加入一个新点的具体操作是什么呢?

我们考虑一个指针指向的元素为 j,那么加入 j 可能会对哪些区间 [i,j] 产生贡献呢?

显然是 [lstj+1,j]lstj 表示左边最后一个与 aj 相等的下标)。

联想到我们对一个静态序列求最大子段和的贪心算法,这个加点操作可以转化为在一些序列中加入一个新的元素,并同时更新这些序列的最大子段和,最后取所有序列中最大值为答案。

具体来说:

对于每个左端点 i ,如果 i可能与它连接并产生贡献的点连接成为一个序列,那么第 k 个询问答案实际上就是以 [li,ri] 中所有每个点开头组成的序列的最大子段和的最大值。

那么我们用一颗线段树来维护这些信息即可。

此时每个序列的最大子段和其实就是更新时的区间和的历史最大值。

code:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10,INF=1e9+7;
int n,m,a[N],lst[N],ans[N];
map<int,int>ptr;
struct Segment_tree{
#define ls (o<<1)
#define rs (o<<1|1)
#define mid ((l+r)>>1)
int tmx[N<<2],tsum[N<<2],htag[N<<2],stag[N<<2];
void pushup(int o){
tsum[o]=max(tsum[ls],tsum[rs]);
tmx[o]=max(tmx[ls],tmx[rs]);
}
void pushdown(int o){
tmx[ls]=max(tmx[ls],tsum[ls]+htag[o]);tmx[rs]=max(tmx[rs],tsum[rs]+htag[o]);
tsum[ls]+=stag[o];tsum[rs]+=stag[o];
htag[ls]=max(htag[ls],stag[ls]+htag[o]);htag[rs]=max(htag[rs],stag[rs]+htag[o]);
stag[ls]+=stag[o];stag[rs]+=stag[o];
stag[o]=htag[o]=0;
}
void add(int o,int l,int r,int s,int t,int k){
if(s<=l&&r<=t){
tsum[o]+=k;tmx[o]=max(tmx[o],tsum[o]);
stag[o]+=k;
htag[o]=max(htag[o],stag[o]);
return;
}
pushdown(o);
if(s<=mid)add(ls,l,mid,s,t,k);
if(mid<t)add(rs,mid+1,r,s,t,k);
pushup(o);
return;
}
int querytmax(int o,int l,int r,int s,int t){
if(s<=l&&r<=t)return tmx[o];
int ret=-INF;
pushdown(o);
if(s<=mid)ret=querytmax(ls,l,mid,s,t);
if(mid<t)ret=max(ret,querytmax(rs,mid+1,r,s,t));
return ret;
}
}tree;
struct query{
int l,r;
int id;
}q[N];
bool cmp(struct query q1,struct query q2){
if(q1.r!=q2.r)return q1.r<q2.r;
return q1.l<q2.l;
}
signed main(){
std::ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++){
lst[i]=ptr[a[i]];
ptr[a[i]]=i;
}
cin>>m;
for(int i=1;i<=m;i++)cin>>q[i].l>>q[i].r,q[i].id=i;
sort(q+1,q+m+1,cmp);
for(int i=1;i<=m;i++){
for(int j=q[i-1].r+1;j<=q[i].r;j++)tree.add(1,1,n,lst[j]+1,j,a[j]);
ans[q[i].id]=tree.querytmax(1,1,n,q[i].l,q[i].r);
}
for(int i=1;i<=m;i++)cout<<ans[i]<<"\n";
return 0;
}

本文作者:little-corn

本文链接:https://www.cnblogs.com/little-corn/p/18157490

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Little_corn  阅读(10)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起