【bzoj 1748】[Ahoi2009]Seq 维护序列seq 裸的线段树

236 篇文章 0 订阅
38 篇文章 0 订阅

其实一开始拿到这一道题把我吓到了,09年的题居然是裸的线段树?怀着半信半疑的态度写了一份,居然过了,qaq

然后第一份代码不知道哪里指针越界了,变量会莫名其妙的在其他地方改变,被迫把所有的int型改成long long强制重新分配内存,然后,long long嘛 时限4000+

维护两个lazy标记一个记录乘一个记录加,然后用手摸你一下改变的过程,然后利用乘法分配率,每次乘的同时还要修改加,每次修改加的时候就只修改加,下方标记的时候先乘再加,最后不知道数据有没有0的,反正保险用一个vis标记修改

#include<cstdio>
#include<cstring>
#include<iostream>
#define maxn 200020
#define LL long long
#define ls u<<1,l,mid
#define rs u<<1|1,mid+1,r
using namespace std;
LL n,m,p;
struct node{
	LL l,r,sum,lazy1,lazy2,vis1,vis2;//lazy1维护乘法 lazy2 维护加法 
}nod[maxn*4];
void push_up(LL u){nod[u].sum=(nod[u<<1].sum+nod[u<<1|1].sum)%p;}
void push_down(LL u){
	if(nod[u].vis1==0&&nod[u].vis2==0)return;
	LL add1=nod[u].lazy1,add2=nod[u].lazy2;LL ll=u<<1,rr=u<<1|1;
	if(nod[u].vis1)nod[ll].vis1=nod[rr].vis1=1;
	if(nod[u].vis2 )nod[ll].vis2=nod[rr].vis2=1;
	nod[ll].lazy1=(nod[ll].lazy1*add1)%p,nod[rr].lazy1=(nod[rr].lazy1*add1)%p;
	nod[ll].lazy2=(nod[ll].lazy2*add1+add2)%p,nod[rr].lazy2=(nod[rr].lazy2*add1+add2)%p;
	nod[ll].sum=(nod[ll].sum*add1+add2*(nod[ll].r-nod[ll].l+1))%p,nod[rr].sum=(nod[rr].sum*add1+add2*(nod[rr].r-nod[rr].l+1))%p;
	nod[u].lazy1=1,nod[u].lazy2=0,nod[u].vis1=nod[u].vis2=0;
}
void build(LL u,LL l,LL r){
	nod[u].vis1=nod[u].vis2=0,nod[u].l=l,nod[u].r=r;nod[u].lazy1=1,nod[u].lazy2=0;
	if(l==r){scanf("%lld",&nod[u].sum);return;}
	LL mid=l+r>>1;
	build(ls),build(rs);
	push_up(u);
}
void update(LL u,LL l,LL r,LL x,LL y,LL add,LL pos){
	if(l==x&&r==y){
		if(pos==1)nod[u].lazy1=(nod[u].lazy1*add)%p,nod[u].lazy2=(nod[u].lazy2*add)%p,nod[u].sum=(nod[u].sum*add)%p,nod[u].vis1=1;
		else nod[u].lazy2=(nod[u].lazy2+add)%p,nod[u].sum=(nod[u].sum+add*(nod[u].r-nod[u].l+1))%p,nod[u].vis2=1;
		return;
	}
	LL mid=l+r>>1;
	push_down(u);
	if(x>mid)update(rs,x,y,add,pos);
	else if(y<=mid)update(ls,x,y,add,pos);
	else update(ls,x,mid,add,pos),update(rs,mid+1,y,add,pos);
	push_up(u);
}
LL query(LL u,LL l,LL r,LL x,LL y){
	if(x==l&&r==y)return nod[u].sum;
	LL mid=l+r>>1;
	push_down(u);
	if(x>mid)return query(rs,x,y)%p;
	else if(y<=mid)return query(ls,x,y)%p;
	else return (query(ls,x,mid)+query(rs,mid+1,y))%p;
}
int main(){
	scanf("%lld%lld",&n,&p);
	build(1,1,n);
	scanf("%lld",&m);
	for(LL pos,a,b,c,i=1;i<=m;i++){
		scanf("%lld%lld%lld",&pos,&a,&b);
		if(pos==1){
			scanf("%lld",&c);update(1,1,n,a,b,c,1);
		}else if(pos==2){
			scanf("%lld",&c);update(1,1,n,a,b,c,2);
		}else{
			printf("%lld\n",query(1,1,n,a,b));
		}
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值