传送门https://www.luogu.com.cn/problem/P2184
这道题一开始写的时候完全没想到解法。没有结合其他算法,算是一个思维题,运用了类差分思想和前缀和思想的处理方式。
这道题的核心在于区间修改。但是我们发现没办法操控修改完之后怎么表示(不能用和的形式)
这里考虑将区间问题转化成端点操作问题
以下图示摘自董晓老师的博客
这样一来,局势就瞬间明了了。
这道题对3-5查询 实际上就是查询1-5的起点减去1-2的终点(前缀和思想)
更实质的说,这里是让1-5所有存在的线段减去在3之前就结束的
起点说明有这一段(因为只有端点,所以不会覆盖),终点说明没有这一段
我的印象中,这道题很经典(以前好像也见过但是没解出来),浅浅记下
贴代码(过于暴力)
// Problem:
// P2184 贪婪大陆
//
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P2184
// Memory Limit: 125 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<iostream>
using namespace std;
int n,m;
const int N=1e5+10;
#define int long long
struct node{
int l,r,suml,addl,sumr,addr;
}tr[N*4];
#define lc u<<1
#define rc u<<1|1
void pushup(int u){
tr[u].sumr=tr[lc].sumr+tr[rc].sumr;
tr[u].suml=tr[lc].suml+tr[rc].suml;
}
void pushdown(int u){
if(tr[u].addl){
tr[lc].suml+=tr[u].addl*(tr[lc].r-tr[lc].l+1);
tr[rc].suml+=tr[u].addl*(tr[rc].r-tr[rc].l+1);
tr[lc].addl+=tr[u].addl;
tr[rc].addl+=tr[u].addl;
tr[u].addl=0;
}
if(tr[u].addr){
tr[lc].sumr+=tr[u].addr*(tr[lc].r-tr[lc].l+1);
tr[rc].sumr+=tr[u].addr*(tr[rc].r-tr[rc].l+1);
tr[lc].addr+=tr[u].addr;
tr[rc].addr+=tr[u].addr;
tr[u].addr=0;
}
}
void build(int u,int l,int r){
tr[u]={l,r};
if(l==r) return;
int m=(l+r)>>1;
build(lc,l,m);
build(rc,m+1,r);
pushup(u);
}
void updatel(int u,int l,int r,int k){
if(l<=tr[u].l&&tr[u].r<=r){
tr[u].suml+=(tr[u].r-tr[u].l+1)*k;
tr[u].addl+=k;
return;
}
pushdown(u);
int m=(tr[u].l+tr[u].r)>>1;
if(l<=m) updatel(lc,l,r,k);
if(r>m) updatel(rc,l,r,k);
pushup(u);
}
void updater(int u,int l,int r,int k){
if(l<=tr[u].l&&tr[u].r<=r){
tr[u].sumr+=(tr[u].r-tr[u].l+1)*k;
tr[u].addr+=k;
return;
}
pushdown(u);
int m=(tr[u].l+tr[u].r)>>1;
if(l<=m) updater(lc,l,r,k);
if(r>m) updater(rc,l,r,k);
pushup(u);
}
int queryl(int u,int l,int r){
if(l<=tr[u].l&&tr[u].r<=r){
return tr[u].suml;
}
pushdown(u);
int m=(tr[u].l+tr[u].r)>>1;
int num=0;
if(l<=m) num=queryl(lc,l,r);
if(r>m) num+=queryl(rc,l,r);
return num;
}
int queryr(int u,int l,int r){
if(l<=tr[u].l&&tr[u].r<=r){
return tr[u].sumr;
}
pushdown(u);
int m=(tr[u].l+tr[u].r)>>1;
int num=0;
if(l<=m) num=queryr(lc,l,r);
if(r>m) num+=queryr(rc,l,r);
return num;
}
signed main(){
cin>>n>>m;
build(1,1,n);
while(m--){
int op,a,b;cin>>op>>a>>b;
if(op==1){
updatel(1,a,a,1);
updater(1,b,b,1);
}
else{
cout<<queryl(1,1,b)-queryr(1,1,a-1)<<endl;
}
}
return 0;
}