2019西北大学集训队选拔赛(重现赛)D.温暖的签到题(线段树)

题目

给你一个长度为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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Code92007

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

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

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

打赏作者

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

抵扣说明:

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

余额充值