题目
给你一个长度为n(n<=1e5)的序列,初始为1,2,3...n,对其进行m(m<=1e5)次操作。
操作有两种:
1 l r,表示将区间[l,r]用[1,2...r-l+1]覆盖
2 l r,查询[l,r]的区间和
思路来源
7个月前不会的题今天一看突然会了
题解
区间覆盖,标记记录"覆盖的等差数列的左端点cov",即操作1的左端点l
对于一个覆盖的区间[l,r],根据区间左右端点到cov的位移
判断出这应该是一段[1+l-cov,1+r-cov]的等差数列,
然后下放,覆盖儿子的标记,
对于询问,维护区间和即可
代码
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int>P;
typedef long long ll;
#define fi first
#define se second
const int N=1e5+10;
int n,m,op,l,r;
struct segtree{
int n;
struct node{int l,r,cov;ll v;}e[N<<2];
#define l(p) e[p].l
#define r(p) e[p].r
#define v(p) e[p].v
#define c(p) e[p].cov
void up(int p){v(p)=v(p<<1)+v(p<<1|1);}
void bld(int p,int l,int r){
l(p)=l;r(p)=r;c(p)=0;
if(l==r){v(p)=l;return;}
int mid=l+r>>1;
bld(p<<1,l,mid);bld(p<<1|1,mid+1,r);
up(p);
}
ll cal(ll l,ll r){
return (l+r)*(r-l+1)/2;
}
void psd(int p){
if(c(p)){
c(p<<1)=c(p);c(p<<1|1)=c(p);
v(p<<1)=cal(1+l(p<<1)-c(p),1+r(p<<1)-c(p));
v(p<<1|1)=cal(1+l(p<<1|1)-c(p),1+r(p<<1|1)-c(p));
c(p)=0;
}
}
void init(int _n){n=_n;bld(1,1,n);}
void chg(int p,int ql,int qr){
if(ql<=l(p)&&r(p)<=qr){
c(p)=ql;
v(p)=cal(1+l(p)-ql,1+r(p)-ql);
return;
}
psd(p);
int mid=l(p)+r(p)>>1;
if(ql<=mid)chg(p<<1,ql,qr);
if(qr>mid)chg(p<<1|1,ql,qr);
up(p);
}
ll ask(int p,int ql,int qr){
if(ql<=l(p)&&r(p)<=qr)return v(p);
int mid=l(p)+r(p)>>1;ll res=0;
psd(p);
if(ql<=mid)res+=ask(p<<1,ql,qr);
if(qr>mid)res+=ask(p<<1|1,ql,qr);
return res;
}
}seg;
int main(){
scanf("%d%d",&n,&m);
seg.init(n);
while(m--){
scanf("%d%d%d",&op,&l,&r);
if(op==1)seg.chg(1,l,r);
else printf("%lld\n",seg.ask(1,l,r));
}
return 0;
}