ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

SP1557 GSS2 - Can you answer these queries II

2022-07-13 08:33:22  阅读:112  来源: 互联网

标签:rs these upd tr SP1557 mid II int MAXN


题意

求区间最大去重后的子段和。

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;
}

标签:rs,these,upd,tr,SP1557,mid,II,int,MAXN
来源: https://www.cnblogs.com/ZCETHAN/p/16472468.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有