SP1557 GSS2 - Can you answer these queries II
题意
求区间最大去重后的子段和。
Solution
考虑到 CF997E 的套路。求区间子段计数的问题,可以采用离线的方式。还是一样考虑移动右端点。那么在线段树上 \(i\) 位置存储 \([i,r]\) 的去重后的子段和。
现在考虑端点移动。加入了一个 \(a_r\),只会对上一次出现 \(a_r\) 的位置之后的位置的值产生影响。所以我们开一个数组,记录一下每个值上一次出现的位置即可,然后在线段树上做区间加。
然后考虑统计答案。对于求区间中最大子区间,同样需要把历史最值给记录下来。和 CF997E 一样,我们考虑通过在线段树上打标记,来记录每一个左端点到右端点最大值的最大值。为了保证复杂度,我们同样需要打一个标记,表示这段区间是否需要取一下区间最大值存到历史最值里去。
写了一下发现了一点问题,只记录是否需要取最大值是不够的,因为有可能当前最优值没有下放然后后面修改的时候直接把这个状态覆盖掉了。所以我们需要把这个标记改成从上一次下放开始到当前加法标记的最大值,这样的话下放的时候直接用这个标记来更新历史最值就不会丢失更优状态了。
Code
const int MAXN=2e5+10;
const int dlt=1e5;
int a[MAXN],pre[MAXN];
vector<pii> qs[MAXN];
struct Tree{int l,r,sum,inc,mx,tag;}tr[MAXN<<2];
#define ls i<<1
#define rs i<<1|1
void pushup(int i){
tr[i].sum=max(tr[ls].sum,tr[rs].sum);
tr[i].mx=max(tr[ls].mx,tr[rs].mx);
}
void add(int i,int v,int t){
tr[i].sum+=v;
tr[i].tag=max(tr[i].tag,tr[i].inc+t);
tr[i].inc+=v;
}
void pushdown(int i){
tr[ls].mx=max(tr[ls].mx,tr[ls].sum+tr[i].tag);
tr[rs].mx=max(tr[rs].mx,tr[rs].sum+tr[i].tag);
add(ls,tr[i].inc,tr[i].tag);
add(rs,tr[i].inc,tr[i].tag);
tr[i].inc=tr[i].tag=0;
}
void build(int i,int l,int r){
tr[i].l=l;tr[i].r=r;tr[i].inc=tr[i].tag=tr[i].mx=0;
if(l==r){tr[i].sum=0;return;}
int mid=(l+r)>>1;build(ls,l,mid);build(rs,mid+1,r);
pushup(i);
}
void upd(int i,int l,int r,int v){
if(tr[i].l==l&&tr[i].r==r){
tr[i].sum+=v;
tr[i].mx=max(tr[i].mx,tr[i].sum);
tr[i].inc+=v;
tr[i].tag=max(tr[i].tag,tr[i].inc);
return;
}pushdown(i);int mid=(tr[i].l+tr[i].r)>>1;
if(r<=mid) upd(ls,l,r,v);else if(l>mid) upd(rs,l,r,v);
else upd(ls,l,mid,v),upd(rs,mid+1,r,v);pushup(i);
}
int ask(int i,int l,int r){
if(tr[i].l==l&&tr[i].r==r) return tr[i].mx;
pushdown(i);int mid=(tr[i].l+tr[i].r)>>1;
if(r<=mid) return ask(ls,l,r);else if(l>mid) return ask(rs,l,r);
else return max(ask(ls,l,mid),ask(rs,mid+1,r));
}
int ans[MAXN];
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int n;cin>>n;
rep(i,1,n) cin>>a[i];
int Q;cin>>Q;
rep(i,1,Q){
int l,r;cin>>l>>r;
qs[r].pb(mkp(l,i));
}build(1,1,n);
rep(i,1,n){
upd(1,pre[a[i]+dlt]+1,i,a[i]);
pre[a[i]+dlt]=i;
for(auto p:qs[i])
ans[p.se]=max(0ll,ask(1,p.fi,i));
}
rep(i,1,Q) cout<<ans[i]<<'\n';
return 0;
}