Ex - I like Query Problem(线段树)

Ex - I like Query Problem

写在前面:

线段树写的最朴素版本,代码较长!

题目大意:

一个序列,三个操作:
区间下取整
区间覆盖
求区间和

思路:

操作一比较经典,当区间最大值的变化量和区间最小值的变化量相同时区间变化量相同。操作变成了一个区间减法一个lazy(可以画个单调递增序列手玩一下)
操作二一个lazy
操作三没什么好说的
线段树需要以下信息:

struct PW{
	int l,r;
	int maxn,minn; // 最值
	ll sum;  // 区间和
	int lazy1,lazy2;  // 区间减 区间覆盖
}a[N*4];

p u s h u p pushup pushup没什么好说的。
考虑 p u s h d o w n pushdown pushdown函数,有两个 l a z y lazy lazy l a z y 2 lazy2 lazy2是区间覆盖要先下放。
注意两个操作的 + = += += = = =

void pushdown(int id){
	if(a[id].lazy2!=0){
		a[id<<1].lazy2=a[id].lazy2;
		a[id<<1].lazy1=0;
		a[id<<1].minn=a[id].lazy2;
		a[id<<1].maxn=a[id].lazy2;
		a[id<<1].sum=(ll)(a[id<<1].r-a[id<<1].l+1)*(ll)a[id].lazy2;
		
		a[id<<1|1].lazy2=a[id].lazy2;
		a[id<<1|1].lazy1=0;
		a[id<<1|1].minn=a[id].lazy2;
		a[id<<1|1].maxn=a[id].lazy2;
		a[id<<1|1].sum=(ll)(a[id<<1|1].r-a[id<<1|1].l+1)*(ll)a[id].lazy2;
	}
	a[id<<1].lazy1+=a[id].lazy1;
	a[id<<1].maxn=a[id<<1].maxn+a[id].lazy1;
	a[id<<1].minn=a[id<<1].minn+a[id].lazy1;
	a[id<<1].sum+=(ll)(a[id<<1].r-a[id<<1].l+1)*(ll)a[id].lazy1;
	
	a[id<<1|1].lazy1+=a[id].lazy1;
	a[id<<1|1].maxn=a[id<<1|1].maxn+a[id].lazy1;
	a[id<<1|1].minn=a[id<<1|1].minn+a[id].lazy1;
	a[id<<1|1].sum+=(ll)(a[id<<1|1].r-a[id<<1|1].l+1)*(ll)a[id].lazy1;
	
	a[id].lazy1=0,a[id].lazy2=0;
}

操作三就是正常的区间修改操作,操作一的写法和区间开根号的写法一致(部分区间修改,部分暴力找到叶子。这种操作有更好的线段树去实现个人有待学习)

void modify1(int id,int l,int r,int x){
	if(a[id].l==a[id].r){
		a[id].maxn=a[id].maxn/x;
		a[id].minn=a[id].minn/x;
		a[id].sum=a[id].sum/x;
	}
	else if(a[id].l>=l&&a[id].r<=r){
		PW s=query(1,a[id].l,a[id].r);
		if(s.maxn-s.maxn/x==s.minn-s.minn/x){
			int c=-(s.maxn-s.maxn/x);
			a[id].lazy1+=c;
			a[id].maxn+=c;
			a[id].minn+=c;
			a[id].sum+=(ll)(a[id].r-a[id].l+1)*(ll)c;
		}
		else{
			pushdown(id);
			int mid=a[id].l+a[id].r>>1;
			if(l<=mid) modify1(id<<1,l,r,x);
			if(r>mid) modify1(id<<1|1,l,r,x);
			pushup(id);
		}
	}
	else{
		pushdown(id);
		int mid=a[id].l+a[id].r>>1;
		if(l<=mid) modify1(id<<1,l,r,x);
		if(r>mid) modify1(id<<1|1,l,r,x);
		pushup(id);
	}
}

Code:

#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <iomanip>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
//#include <unordered_map>
#define guo312 std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define ll long long
#define Inf LONG_LONG_MAX
#define inf INT_MAX
#define endl "\n"
#define PI 3.1415926535898
using namespace std;
const int N=5e5+10;
int val[N];

struct PW{
	int l,r;
	int maxn,minn;
	ll sum;
	int lazy1,lazy2;
}a[N*4];

void pushup(PW &s1,PW &s2,PW &s3){
	s3.maxn=max(s1.maxn,s2.maxn);
	s3.minn=min(s1.minn,s2.minn);
	s3.sum=s1.sum+s2.sum;
	s3.lazy1=0,s3.lazy2=0;
}

void pushup(int id){
	pushup(a[id<<1],a[id<<1|1],a[id]);
}

void pushdown(int id){
	if(a[id].lazy2!=0){
		a[id<<1].lazy2=a[id].lazy2;
		a[id<<1].lazy1=0;
		a[id<<1].minn=a[id].lazy2;
		a[id<<1].maxn=a[id].lazy2;
		a[id<<1].sum=(ll)(a[id<<1].r-a[id<<1].l+1)*(ll)a[id].lazy2;
		
		a[id<<1|1].lazy2=a[id].lazy2;
		a[id<<1|1].lazy1=0;
		a[id<<1|1].minn=a[id].lazy2;
		a[id<<1|1].maxn=a[id].lazy2;
		a[id<<1|1].sum=(ll)(a[id<<1|1].r-a[id<<1|1].l+1)*(ll)a[id].lazy2;
	}
	a[id<<1].lazy1+=a[id].lazy1;
	a[id<<1].maxn=a[id<<1].maxn+a[id].lazy1;
	a[id<<1].minn=a[id<<1].minn+a[id].lazy1;
	a[id<<1].sum+=(ll)(a[id<<1].r-a[id<<1].l+1)*(ll)a[id].lazy1;
	
	a[id<<1|1].lazy1+=a[id].lazy1;
	a[id<<1|1].maxn=a[id<<1|1].maxn+a[id].lazy1;
	a[id<<1|1].minn=a[id<<1|1].minn+a[id].lazy1;
	a[id<<1|1].sum+=(ll)(a[id<<1|1].r-a[id<<1|1].l+1)*(ll)a[id].lazy1;
	
	a[id].lazy1=0,a[id].lazy2=0;
}

void build(int id,int l,int r){
	a[id].l=l,a[id].r=r;
	if(l==r){
		a[id].lazy1=0,a[id].lazy2=0;
		a[id].maxn=val[l],a[id].minn=val[l];
		a[id].sum=val[l];
	}
	else{
		int mid=l+r>>1;
		build(id<<1,l,mid),build(id<<1|1,mid+1,r);
		pushup(id);
	}
}

PW query(int id,int l,int r){
	if(a[id].l>=l&&a[id].r<=r){
		return a[id];
	}
	else{
		pushdown(id);
		int mid=a[id].l+a[id].r>>1;
		if(r<=mid){
			return query(id<<1,l,r);
		}
		else if(l>mid){
			return query(id<<1|1,l,r);
		}
		else{
			PW s1=query(id<<1,l,r);
			PW s2=query(id<<1|1,l,r);
			PW s3;
			pushup(s1,s2,s3);
			return s3;
		}
	}
}

void modify1(int id,int l,int r,int x){
	if(a[id].l==a[id].r){
		a[id].maxn=a[id].maxn/x;
		a[id].minn=a[id].minn/x;
		a[id].sum=a[id].sum/x;
	}
	else if(a[id].l>=l&&a[id].r<=r){
		PW s=query(1,a[id].l,a[id].r);
		if(s.maxn-s.maxn/x==s.minn-s.minn/x){
			int c=-(s.maxn-s.maxn/x);
			a[id].lazy1+=c;
			a[id].maxn+=c;
			a[id].minn+=c;
			a[id].sum+=(ll)(a[id].r-a[id].l+1)*(ll)c;
		}
		else{
			pushdown(id);
			int mid=a[id].l+a[id].r>>1;
			if(l<=mid) modify1(id<<1,l,r,x);
			if(r>mid) modify1(id<<1|1,l,r,x);
			pushup(id);
		}
	}
	else{
		pushdown(id);
		int mid=a[id].l+a[id].r>>1;
		if(l<=mid) modify1(id<<1,l,r,x);
		if(r>mid) modify1(id<<1|1,l,r,x);
		pushup(id);
	}
}

void modify2(int id,int l,int r,int y){
	if(a[id].l>=l&&a[id].r<=r){
		a[id].lazy1=0,a[id].lazy2=y;
		a[id].maxn=y,a[id].minn=y;
		a[id].sum=(ll)(a[id].r-a[id].l+1)*(ll)y;
	}
	else{
		pushdown(id);
		int mid=a[id].l+a[id].r>>1;
		if(r<=mid){
			modify2(id<<1,l,r,y);
		}
		else if(l>mid){
			modify2(id<<1|1,l,r,y);
		}
		else{
			modify2(id<<1,l,r,y);
			modify2(id<<1|1,l,r,y);
		}
		pushup(id);
	}
}

int main(){
guo312;
	int n,q; cin>>n>>q;
	for(int i=1;i<=n;i++){
		cin>>val[i];
	}
	build(1,1,n);
	while(q--){
		int op; cin>>op;
		if(op==1){
			int l,r,x; cin>>l>>r>>x;
			modify1(1,l,r,x);
		}
		else if(op==2){
			int l,r,y; cin>>l>>r>>y;
			modify2(1,l,r,y);
		}
		else{
			int l,r; cin>>l>>r;
			cout<<query(1,l,r).sum<<endl; 
		}
	}
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

要用bug来打败bug

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值