题面
思路一、
将清空操作视为区间最小值操作
不知道区间操作点我
#include <iostream>
#define lc (p<<1)
#define rc (p<<1|1)
using namespace std;
const int N = 1e5+10;
typedef long long ll;
struct Node{
int l,r,mx,sec_mx,mx_num;
int mx_tag,other_tag;
ll sum;
}tr[N<<2];
int a[N],t,n,m;
void push_down(int p);
void push_up(int p){
tr[p].sum = tr[lc].sum + tr[rc].sum;
if(tr[lc].mx == tr[rc].mx){
tr[p].mx = tr[lc].mx;
tr[p].mx_num = tr[lc].mx_num + tr[rc].mx_num;
tr[p].sec_mx = max(tr[lc].sec_mx,tr[rc].sec_mx);
}else if(tr[lc].mx > tr[rc].mx){
tr[p].mx = tr[lc].mx;
tr[p].mx_num = tr[lc].mx_num;
tr[p].sec_mx = max(tr[lc].sec_mx,tr[rc].mx);
}else{
tr[p].mx = tr[rc].mx;
tr[p].mx_num = tr[rc].mx_num;
tr[p].sec_mx = max(tr[rc].sec_mx,tr[lc].mx);
}
}
void build(int p,int l,int r){
tr[p].l = l,tr[p].r = r;
tr[p].sec_mx = -1;//因为数据范围是从0开始的
tr[p].mx_tag = tr[p].other_tag = 0;
if(l == r){
tr[p].sum = tr[p].mx = a[l];
tr[p].mx_num = 1;
return;
}
int mid = (l+r) >> 1;
build(lc,l,mid);
build(rc,mid+1,r);
push_up(p);
}
//给这个节点的最大值、其他值加上某些数
void node_update_fun(int p,int mxk,int otherk){
tr[p].sum += 1ll*mxk*tr[p].mx_num + 1ll*(tr[p].r-tr[p].l+1-tr[p].mx_num)*otherk;
if(tr[p].sec_mx != -1) tr[p].sec_mx += otherk;
tr[p].mx += mxk;
tr[p].mx_tag += mxk;
tr[p].other_tag += otherk;
}
void range_min_fun(int p,int l,int r,int k){
if(k>=tr[p].mx) return;
if(tr[p].l>=l&&tr[p].r<=r&&tr[p].sec_mx < k){
node_update_fun(p,k-tr[p].mx,0);
return;
}
push_down(p);
int mid = (tr[p].l + tr[p].r) >> 1;
if(r<=mid){
range_min_fun(lc,l,r,k);
}else if(l>mid){
range_min_fun(rc,l,r,k);
}else{
range_min_fun(lc,l,mid,k);
range_min_fun(rc,mid+1,r,k);
}
push_up(p);
}
void push_down(int p){
int mxk = tr[p].mx_tag;
int otherk = tr[p].other_tag;
int mx = max(tr[lc].mx,tr[rc].mx);
//分清楚左右儿子的值到底应该被哪个k所加
node_update_fun(lc,tr[lc].mx==mx?mxk:otherk,otherk);
node_update_fun(rc,tr[rc].mx==mx?mxk:otherk,otherk);
tr[p].mx_tag = tr[p].other_tag = 0;
}
ll query_sum(int p,int l,int r){
if(tr[p].l>=l&&tr[p].r<=r){
return tr[p].sum;
}
push_down(p);
int mid = (tr[p].l+tr[p].r)>>1;
if(r<=mid){
return query_sum(lc,l,r);
}else if(l>mid){
return query_sum(rc,l,r);
}else{
return query_sum(lc,l,mid) +
query_sum(rc,mid+1,r);
}
}
void range_add_fun(int p,int l,int r,int k){
if(tr[p].l>=l&&tr[p].r<=r){
node_update_fun(p,k,k);
return;
}
push_down(p);
int mid = (tr[p].l + tr[p].r) >> 1;
if(r<=mid){
range_add_fun(lc,l,r,k);
}else if(l > mid){
range_add_fun(rc,l,r,k);
}else{
range_add_fun(lc,l,mid,k);
range_add_fun(rc,mid+1,r,k);
}
push_up(p);
}
int main(){
std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
ll n,q;
cin >> n >> q;
for(ll i=1;i<=n;++i) a[i] = 0;
build(1,1,n);
ll l,r,m;
while(q--){
cin >> m >> l >> r;
if(m==0 && l&1 && r&1){
//区间清空
range_min_fun(1,l,r,0);
}else{
if(m == 0){
//区间和
cout << query_sum(1,l,r) << '\n';
}else{
//区间加
range_add_fun(1,l,r,m);
}
}
}
return 0;
}
/**************************************************************
Problem: 2053
Language: C++
Result: 正确
Time:2066 ms
Memory:18356 kb
****************************************************************/
思路二、
维护清空标记;
在push_down的时候,先执行clear标记,再执行add标记;
因为打上clear的同时,会将add清空;
如果再有标记,则说明是清空后的标记;
#include <iostream>
#define lc (p<<1)
#define rc (p<<1|1)
using namespace std;
const int N = 1e5+10;
typedef long long ll;
struct Node{
int l,r;
ll sum,add;
bool clear;
}t[N<<2];
ll a[N];
void push_up(int p){
t[p].sum = t[lc].sum + t[rc].sum;
}
void push_down(int p){
auto & r = t[p];
auto & left = t[lc];
auto & right = t[rc];
if(r.clear){
left.sum = 0;
right.sum = 0;
left.add = right.add = 0;
left.clear = right.clear = true;
r.clear = false;
}
if(r.add){
left.sum += 1ll*(left.r - left.l +1)*r.add;
left.add += r.add;
right.sum += 1ll*(right.r - right.l +1)*r.add;
right.add +=r.add;
r.add = 0;
}
}
void build(int p,int l,int r){
t[p].l = l,t[p].r = r;
t[p].clear = false;
if(l == r){
t[p].sum = a[l];
t[p].add = 0;
return;
}
int mid = (l+r) >> 1;
build(lc,l,mid);
build(rc,mid+1,r);
push_up(p);
}
void modify(int p,int l,int r,int d){
if(t[p].l>=l&&t[p].r<=r){
t[p].sum += (t[p].r-t[p].l+1)*d;
t[p].add += d;
return;
}
push_down(p);
int mid = (t[p].l+t[p].r) >> 1;
if(r<=mid) modify(lc,l,r,d);
else if(l>mid) modify(rc,l,r,d);
else{
modify(lc,l,mid,d);
modify(rc,mid+1,r,d);
}
push_up(p);
}
ll query(int p,int l,int r){
if(t[p].l>=l&&t[p].r<=r){
return t[p].sum;
}
push_down(p);
int mid = (t[p].l+t[p].r) >> 1;
if(r<=mid) return query(lc,l,r);
else if(l>mid) return query(rc,l,r);
else{
return query(lc,l,mid) + query(rc,mid+1,r);
}
}
void clear(int p,int l,int r){
if(t[p].l>=l&&t[p].r<=r){
t[p].sum = 0;
t[p].add = 0;
t[p].clear = true;
return;
}
push_down(p);
int mid = (t[p].l+t[p].r)>>1;
if(r<=mid) clear(lc,l,r);
else if(l>mid) clear(rc,l,r);
else{
clear(lc,l,mid);
clear(rc,mid+1,r);
}
push_up(p);
}
int main(){
std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int n,q;
cin >> n >> q;
for(int i=1;i<=n;++i) a[i] = 0;
build(1,1,n);
int l,r,m;
while(q--){
cin >> m >> l >> r;
if(m==0 && l&1 && r&1){
clear(1,l,r);
}else{
if(m == 0){
cout << query(1,l,r) << '\n';
}else{
modify(1,l,r,m);
}
}
}
return 0;
}
思路三、
维护两个标记,覆盖标记以及加法标记;
当有覆盖标记的时候,加法标记可以转化为覆盖标记;
代码部分待补;
#include <iostream>
#define lc (p<<1)
#define rc (p<<1|1)
using namespace std;
const int N = 1e5+10;
typedef long long ll;
const int INF = 0x3f3f3f3f;
int a[N];
struct Node{
int l,r,add,cover;
ll sum;
bool cover_tag;
}tr[N<<2];
void push_up(int p){
tr[p].sum = tr[lc].sum + tr[rc].sum;
}
//给某个区间加上k
void node_add(int p,int k){
tr[p].sum += (tr[p].r-tr[p].l+1)*k;
//如果有tag 则将add转化为cover操作
if(tr[p].cover_tag){
tr[p].cover += k;
}else{
tr[p].add += k;
}
}
//将某个节点的值覆盖成k
void node_cover(int p,int k){
tr[p].sum = (tr[p].r-tr[p].l+1) * k;
tr[p].cover = k;
tr[p].cover_tag = 1;
}
//先add再cover,因为如果有cover的话会将add转为cover
//见node_add部分代码
void push_down(int p){
if(tr[p].add){
node_add(lc,tr[p].add);
node_add(rc,tr[p].add);
tr[p].add = 0;
}
if(tr[p].cover_tag){
node_cover(lc,tr[p].cover);
node_cover(rc,tr[p].cover);
tr[p].cover_tag = 0;
}
}
void build(int p,int l,int r){
tr[p].l = l,tr[p].r = r;
if(l == r){
tr[p].sum = a[l];
return;
}
int mid = (l+r) >> 1;
if(r<=mid){
build(lc,l,r);
}else if(l>mid){
build(rc,l,r);
}else{
build(lc,l,mid);
build(rc,mid+1,r);
}
push_up(p);
}
void range_cover(int p,int l,int r,int k){
if(tr[p].l>=l&&tr[p].r<=r){
node_cover(p,k);
return;
}
push_down(p);
int mid = (tr[p].l + tr[p].r) >> 1;
if(r<=mid){
range_cover(lc,l,r,k);
}else if(l>mid){
range_cover(rc,l,r,k);
}else{
range_cover(lc,l,mid,k);
range_cover(rc,mid+1,r,k);
}
push_up(p);
}
void range_add(int p,int l,int r,int k){
if(tr[p].l>=l&&tr[p].r<=r){
node_add(p,k);
return;
}
push_down(p);
int mid = (tr[p].l + tr[p].r) >> 1;
if(r<=mid){
range_add(lc,l,r,k);
}else if(l>mid){
range_add(rc,l,r,k);
}else{
range_add(lc,l,mid,k);
range_add(rc,mid+1,r,k);
}
push_up(p);
}
ll query_sum(int p,int l,int r){
if(tr[p].l>=l&&tr[p].r<=r){
return tr[p].sum;
}
push_down(p);
int mid = (tr[p].l + tr[p].r) >> 1;
if(r<=mid){
return query_sum(lc,l,r);
}else if(l>mid){
return query_sum(rc,l,r);
}else{
return query_sum(lc,l,mid) +
query_sum(rc,mid+1,r);
}
}
int main(){
std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int n,q;
cin >> n >> q;
for(int i=1;i<=n;++i) a[i] = 0;
build(1,1,n);
int l,r,m;
while(q--){
cin >> m >> l >> r;
if(m==0 && l&1 && r&1){
range_cover(1,l,r,0);
}else{
if(m == 0){
cout << query_sum(1,l,r) << '\n';
}else{
range_add(1,l,r,m);
}
}
}
return 0;
}
/**************************************************************
Problem: 2053
Language: C++
Result: 正确
Time:1102 ms
Memory:15228 kb
****************************************************************/