2023“钉耙编程”中国大学生算法设计超级联赛(1)Easy problem I

2023“钉耙编程”中国大学生算法设计超级联赛(1)Easy problem I

题目大意

有一个长度为 n n n的数组 a a a,有 m m m次操作,操作类型有两种:

  • 1   l   r   x j 1 \ l \ r \ x_j 1 l r xj,对于每个 i ∈ [ l , r ] i\in[l,r] i[l,r],令 a i = ∣ a i − x j ∣ a_i=|a_i-x_j| ai=aixj
  • 2   l   r 2 \ l \ r 2 l r,输出 a n s = ∑ i = l r a i ans=\sum\limits_{i=l}^ra_i ans=i=lrai

其中 x j ≤ x j + 1 x_j\leq x_{j+1} xjxj+1

t t t组数据。

1 ≤ t ≤ 5 , 1 ≤ n ≤ 2 × 1 0 5 , 1 ≤ m ≤ 2 × 1 0 5 1\leq t\leq 5,1\leq n\leq 2\times 10^5,1\leq m\leq 2\times 10^5 1t5,1n2×105,1m2×105


题解

我们可以根据绝对值来在线段树上分别维护。

对于 a i ≥ x a_i\geq x aix的情况,直接用线段树维护。对于满足 a i ≥ x a_i\geq x aix的一段, a i = a i − x a_i=a_i-x ai=aix,整段减去 x x x即可。

对于 a i < x a_i<x ai<x的情况, a i = x − a i a_i=x-a_i ai=xai,相当于将 a i a_i ai取反再加上 x x x。每次改变时 a i a_i ai的数值不变化,只有符号在改变,则在线段树上可以维护符号的正负和要增加的数。

因为 x j ≤ x j + 1 x_j\leq x_{j+1} xjxj+1,当 a i < a j a_i<a_j ai<aj时, ∣ a i − x j ∣ ≤ x j ≤ x j + 1 |a_i-x_j|\leq x_j\leq x_{j+1} aixjxjxj+1,所以当从 a i ≥ x a_i\geq x aix的状态变为 a i < x a_i<x ai<x的状态之后就不会改变,那么改变的次数是有限的。

转变一个位置的状态的时间复杂度为 O ( l o g n ) O(log n) O(logn),最多会转变 n n n个位置,时间复杂度为 O ( n log ⁡ n ) O(n\log n) O(nlogn)。操作中除去转变状态以外的部分的时间复杂度为 O ( m log ⁡ n ) O(m\log n) O(mlogn)。所以总时间复杂度为 O ( n log ⁡ n + m log ⁡ n ) O(n\log n+m\log n) O(nlogn+mlogn)

code

#include<bits/stdc++.h>
#define lc k<<1
#define rc k<<1|1
using namespace std;
int tq,n,m,a[200005];
long long ans;
struct node{
	long long sum1,sum2,mn,v,ly1,ly2,ly3;
}tr[1000005];
void up(int k){
	tr[k].ly1=tr[k].ly3=0;
	tr[k].ly2=1;
	tr[k].mn=min(tr[lc].mn,tr[rc].mn);
	tr[k].sum1=tr[lc].sum1+tr[rc].sum1;
	tr[k].sum2=tr[lc].sum2+tr[rc].sum2;
	tr[k].v=tr[lc].v+tr[rc].v;
}
void down(int k,int l,int r){
	int mid=l+r>>1;
	
	tr[lc].ly1+=tr[k].ly1;
	tr[rc].ly1+=tr[k].ly1;
	tr[lc].sum1-=tr[k].ly1*tr[lc].v;
	tr[rc].sum1-=tr[k].ly1*tr[rc].v;
	tr[lc].mn-=tr[k].ly1;
	tr[rc].mn-=tr[k].ly1;
	
	tr[lc].ly2*=tr[k].ly2;
	tr[rc].ly2*=tr[k].ly2;
	tr[lc].ly3=tr[k].ly3+tr[lc].ly3*tr[k].ly2;
	tr[rc].ly3=tr[k].ly3+tr[rc].ly3*tr[k].ly2;
	tr[lc].sum2=tr[k].ly3*(mid-l+1-tr[lc].v)+tr[lc].sum2*tr[k].ly2;
	tr[rc].sum2=tr[k].ly3*(r-mid-tr[rc].v)+tr[rc].sum2*tr[k].ly2;
	
	tr[k].ly1=tr[k].ly3=0;
	tr[k].ly2=1;
}
void build(int k,int l,int r){
	if(l==r){
		tr[k].ly1=tr[k].ly3=0;
		tr[k].ly2=1;
		tr[k].mn=tr[k].sum1=a[l];
		tr[k].sum2=0;
		tr[k].v=1;
		return;
	}
	int mid=l+r>>1;
	build(lc,l,mid);
	build(rc,mid+1,r);
	up(k);
}
void ch(int k,int l,int r,int x,int y,int c){
	if(l>=x&&r<=y){
		if(tr[k].v){
			if(l==r){
				if(tr[k].mn<c){
					tr[k].sum2=c-tr[k].sum1;
					tr[k].sum1=tr[k].v=0;
					tr[k].mn=1e18;
				}
				else{
					tr[k].sum1=tr[k].mn=tr[k].sum1-c;
				}
			}
			else{
				if(tr[k].mn<c){
					down(k,l,r);
					int mid=l+r>>1;
					ch(lc,l,mid,x,y,c);
					ch(rc,mid+1,r,x,y,c);
					up(k);
				}
				else{
					tr[k].ly1+=c;
					tr[k].mn-=c;
					tr[k].sum1-=1ll*c*tr[k].v;
					tr[k].ly2*=-1;
					tr[k].ly3=c-tr[k].ly3;
					tr[k].sum2=1ll*c*(r-l+1-tr[k].v)-tr[k].sum2;
				}
			}
		}
		else{
			tr[k].ly2*=-1;
			tr[k].ly3=c-tr[k].ly3;
			tr[k].sum2=1ll*c*(r-l+1)-tr[k].sum2;
		}
		return;
	}
	down(k,l,r);
	int mid=l+r>>1;
	if(x<=mid) ch(lc,l,mid,x,y,c);
	if(y>mid) ch(rc,mid+1,r,x,y,c);
	up(k);
}
void find(int k,int l,int r,int x,int y){
	if(l>=x&&r<=y){
		ans+=tr[k].sum1+tr[k].sum2;
		return;
	}
	down(k,l,r);
	int mid=l+r>>1;
	if(x<=mid) find(lc,l,mid,x,y);
	if(y>mid) find(rc,mid+1,r,x,y);
}
int main()
{
	scanf("%d",&tq);
	while(tq--){
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
		}
		build(1,1,n);
		for(int i=1,tp,l,r,x;i<=m;i++){
			scanf("%d",&tp);
			if(tp==1){
				scanf("%d%d%d",&l,&r,&x);
				ch(1,1,n,l,r,x);
			}
			else{
				scanf("%d%d",&l,&r);
				ans=0;
				find(1,1,n,l,r);
				printf("%lld\n",ans);
			}
		}
	}
	return 0;
}
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值