HDU4578 题解(线段树+耐心)

本文详细解释了如何使用线段树解决支持区间加、乘、赋值的问题,并强调了懒标记在计算区间和、平方和、立方和时的作用。通过实例展示了如何更新和查询区间值,以及为何常规题解可能会导致TLE。
摘要由CSDN通过智能技术生成

传送门(vjudge):HDU4578

题意

支持区间加,区间乘,区间赋值;查询区间和、平方和、立方和。

思路

没啥好犹豫的,肯定是线段树,但是这题考察了我们对懒标记的理解。

线段树板子的懒标记有两个, l z 1 lz_1 lz1 是乘标记, l z 2 lz_2 lz2 是加标记,那么下传懒标记的时候就是:

s ← s × l z 1 + l z 2 × ( r − l + 1 ) s\gets s \times lz_1 + lz_2 \times (r-l+1) ss×lz1+lz2×(rl+1)

你有没有想过为什么?

∑ ( a i × b + c ) = ∑ a i × b + ∑ c = b × ∑ a i + ( r − l + 1 ) × c \begin{aligned} \sum (a_i \times b +c) &= \sum a_i\times b + \sum c \\ &=\color{red} b \times \sum a_i + (r-l+1)\times c \end{aligned} (ai×b+c)=ai×b+c=b×ai+(rl+1)×c

这也是这道题“区间和”下传懒标记的方法。

我们用 s 1 s_1 s1 表示区间和, s 2 s_2 s2 表示平方和, s 3 s_3 s3 表示立方和, x x x 表示当前区间乘懒标记, b b b 表示加懒标记,则有:

s 1 = ∑ ( a i x + b ) = x ∑ a i + ( r − l + 1 ) b \color{black} \begin{aligned}s_1 &= \sum (a_i x+b) \\ &= x \color {red} \sum a_i \color{black} + (r-l+1)b \end{aligned} s1=(aix+b)=xai+(rl+1)b

s 2 = ∑ ( a i x + b ) 2 = ∑ ( x 2 a i 2 + 2 b x a i + b 2 ) = x 2 ∑ a i 2 + 2 b x ∑ a i + ( r − l + 1 ) b 2 \color{black} \begin{aligned} s_2 &= \sum(a_i x + b)^2 \\ &= \sum(x^2a_i^2 + 2bxa_i + b^2) \\ &= x^2 \color{red} \sum a_i^2 \color{black} + 2bx \color{red} \sum a_i \color{black} + (r-l+1)b^2 \end{aligned} s2=(aix+b)2=(x2ai2+2bxai+b2)=x2ai2+2bxai+(rl+1)b2

s 3 = ∑ ( a i x + b ) 3 = ∑ ( x 3 a i 3 + 3 b x 2 a i 2 + 3 b 2 x a i + b 3 ) = x 3 ∑ a i 3 + 3 b x 2 ∑ a i 2 + 3 b 2 x ∑ a i + ( r − l + 1 ) b 3 \color{black} \begin{aligned} s_3 &= \sum (a_ix+b)^3 \\ &= \sum(x^3a_i^3 + 3bx^2a_i^2 + 3b^2x a_i +b^3) \\ &=x^3 \color{red} \sum a_i^3 \color{black} + 3bx^2\color{red}\sum a_i^2 \color{black} + 3b^2x \color{red} \sum a_i \color{black} + (r-l+1)b^3 \end{aligned} s3=(aix+b)3=(x3ai3+3bx2ai2+3b2xai+b3)=x3ai3+3bx2ai2+3b2xai+(rl+1)b3

我们发现标红的部分就是更新前的 s 1 , s 2 , s 3 s_1,s_2,s_3 s1,s2,s3,所以直接更新就行了,但要注意要先更新 s 3 s_3 s3,再 s 2 s_2 s2,接着 s 1 s_1 s1,最后更新懒标记。

代码

#include<cstdio>
using namespace std;
int n,m,s1[400000],s2[400000],s3[400000],lz1[400000],lz2[400000],op,x,y,c1,c2,c3;
void build(int l,int r,int rt){
	s1[rt]=s2[rt]=s3[rt]=lz2[rt]=0,lz1[rt]=1;
	if(l==r)return;
	int mid=l+r>>1;
	build(l,mid,rt<<1),build(mid+1,r,rt<<1|1);
}
void pd(int l,int r,int rt){
	if(lz1[rt]==1&&!lz2[rt])return;
	int mid=l+r>>1,a2=lz2[rt]*lz2[rt]%10007,a3=a2*lz2[rt]%10007,x2=lz1[rt]*lz1[rt]%10007,x3=lz1[rt]*x2%10007;
	s3[rt<<1]=(s3[rt<<1]*x3+3*x2*lz2[rt]%10007*s2[rt<<1]+3*a2*lz1[rt]%10007*s1[rt<<1]+(mid-l+1)*a3)%10007,s3[rt<<1|1]=(s3[rt<<1|1]*x3+3*lz2[rt]*x2%10007*s2[rt<<1|1]+3*a2*s1[rt<<1|1]%10007*lz1[rt]+(r-mid)*a3)%10007,s2[rt<<1]=(s2[rt<<1]*x2+2*lz2[rt]*s1[rt<<1]%10007*lz1[rt]+(mid-l+1)*a2)%10007,s2[rt<<1|1]=(s2[rt<<1|1]*x2+2*lz2[rt]*s1[rt<<1|1]%10007*lz1[rt]+(r-mid)*a2)%10007,s1[rt<<1]=(s1[rt<<1]*lz1[rt]+(mid-l+1)*lz2[rt])%10007,s1[rt<<1|1]=(s1[rt<<1|1]*lz1[rt]+(r-mid)*lz2[rt])%10007,lz1[rt<<1]=lz1[rt<<1]*lz1[rt]%10007,lz1[rt<<1|1]=lz1[rt<<1|1]*lz1[rt]%10007,lz2[rt<<1]=(lz2[rt<<1]*lz1[rt]+lz2[rt])%10007,lz2[rt<<1|1]=(lz2[rt<<1|1]*lz1[rt]+lz2[rt])%10007,lz1[rt]=1,lz2[rt]=0;
	return;
}
void add(int l,int r,int rt){
	if(x<=l&&r<=y){s3[rt]=(s3[rt]+3*s2[rt]*c1+3*s1[rt]*c2+(r-l+1)*c3)%10007,s2[rt]=(s2[rt]+2*s1[rt]*c1+(r-l+1)*c2)%10007,s1[rt]=(s1[rt]+(r-l+1)*c1)%10007,lz2[rt]=(lz2[rt]+c1)%10007;return;}
	pd(l,r,rt);
	int mid=l+r>>1;
	if(mid>=x)add(l,mid,rt<<1);
	if(mid<y)add(mid+1,r,rt<<1|1);
	s1[rt]=(s1[rt<<1]+s1[rt<<1|1])%10007,s2[rt]=(s2[rt<<1]+s2[rt<<1|1])%10007,s3[rt]=(s3[rt<<1]+s3[rt<<1|1])%10007;
	return;
}
void mul(int l,int r,int rt){
	if(x<=l&&r<=y){s3[rt]=s3[rt]*c3%10007,s2[rt]=s2[rt]*c2%10007,s1[rt]=s1[rt]*c1%10007,lz1[rt]=lz1[rt]*c1%10007,lz2[rt]=lz2[rt]*c1%10007;return;}
	pd(l,r,rt);
	int mid=l+r>>1;
	if(mid>=x)mul(l,mid,rt<<1);
	if(mid<y)mul(mid+1,r,rt<<1|1);
	s1[rt]=(s1[rt<<1]+s1[rt<<1|1])%10007,s2[rt]=(s2[rt<<1]+s2[rt<<1|1])%10007,s3[rt]=(s3[rt<<1]+s3[rt<<1|1])%10007;
	return;
}
int query1(int l,int r,int rt){
	if(x<=l&&r<=y)return s1[rt];
	pd(l,r,rt);
	int mid=l+r>>1,ret=0;
	if(mid>=x)ret=query1(l,mid,rt<<1);
	if(mid<y)ret+=query1(mid+1,r,rt<<1|1);
	return ret%10007;
}
int query2(int l,int r,int rt){
	if(x<=l&&r<=y)return s2[rt];
	pd(l,r,rt);
	int mid=l+r>>1,ret=0;
	if(mid>=x)ret=query2(l,mid,rt<<1);
	if(mid<y)ret+=query2(mid+1,r,rt<<1|1);
	return ret%10007;
}
int query3(int l,int r,int rt){
	if(x<=l&&r<=y)return s3[rt];
	pd(l,r,rt);
	int mid=l+r>>1,ret=0;
	if(mid>=x)ret=query3(l,mid,rt<<1);
	if(mid<y)ret+=query3(mid+1,r,rt<<1|1);
	return ret%10007;
}
void clear(int l,int r,int rt){
	if(x<=l&&r<=y){s1[rt]=s2[rt]=s3[rt]=lz1[rt]=lz2[rt]=0;return;}
	pd(l,r,rt);
	int mid=l+r>>1;
	if(mid>=x)clear(l,mid,rt<<1);
	if(mid<y)clear(mid+1,r,rt<<1|1);
	s1[rt]=(s1[rt<<1]+s1[rt<<1|1])%10007,s2[rt]=(s2[rt<<1]+s2[rt<<1|1])%10007,s3[rt]=(s3[rt<<1]+s3[rt<<1|1])%10007;
	return;
}
int main(){
	while(~scanf("%d%d",&n,&m)&&(n||m)){
		build(1,n,1);
		while(m--){
			scanf("%d%d%d%d",&op,&x,&y,&c1),c2=c1*c1%10007,c3=c1*c2%10007;
			if(op==1)add(1,n,1);
			if(op==2)mul(1,n,1);
			if(op==3)clear(1,n,1),add(1,n,1);
			if(op==4){
				if(c1==1)printf("%d\n",query1(1,n,1));
				if(c1==2)printf("%d\n",query2(1,n,1));
				if(c1==3)printf("%d\n",query3(1,n,1));
			}
		}
	}
	return 0;
}

真是的,为什么网上好多题解都会TLE,想贺题解都不行。

  • 24
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值