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