hdu4578 Transformation(线段树/区间加区间乘区间赋值区间立方和)

题意

样例最多10组,每组给你一个长度为n(n<=1e5)的数组,初始为0,

以下m(m<=1e5)次操作,操作分4种

1 x y c 区间+c

2 x y c 区间*c

3 x y c 区间赋值为c

前三种操作,保证c<=10000

4 x y c(1<=c<=3) 询问区间c次方和模10007的值

思路来源

校赛

题解

维护区间立方和、平方和、和,由于立方和就要维护这三个值,实际相当于就询问一个立方和

根据立方和公式、平方和公式推导出标记需要加的部分,

注意优先级 区间赋值>区间乘>区间加

区间赋值时,将区间赋值标记值v,区间乘标记置1,区间加标记置0

区间乘时,将区间乘标记*=v,区间加标记*=v

区间加时,仅将区间加标记+=v即可

实际并不复杂,然而很考验代码熟练度吧,写错一处查了好久QAQ

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e5+10,M=10007;
int pf[M+5],lf[M+5];
int n,m,op,x,y,v; 
struct node
{
	int l,r;
	int add,mul,cov,a[3];//加 乘 赋值 区间1-3次方和 
}e[5*N];
void ADD(int &x,int y)
{
	x+=y;
	if(x>=M)x-=M;
	if(x<0)x+=M; 
}
void MUL(int &x,int y)
{
	x*=y;
	x%=M;
}
void pushup(int p)
{
	for(int i=0;i<3;++i)
	e[p].a[i]=(e[p<<1].a[i]+e[p<<1|1].a[i])%M;
}
void pushdown(int p)
{
	int l=e[p<<1].r-e[p<<1].l+1,r=e[p<<1|1].r-e[p<<1|1].l+1;
	if(e[p].cov)
	{
		int v=e[p].cov;
		e[p<<1].cov=e[p<<1|1].cov=v;
		e[p<<1].mul=e[p<<1|1].mul=1; 
		e[p<<1].add=e[p<<1|1].add=0;
		e[p<<1].a[2]=1ll*l*lf[v]%M,e[p<<1|1].a[2]=1ll*r*lf[v]%M;
		e[p<<1].a[1]=1ll*l*pf[v]%M,e[p<<1|1].a[1]=1ll*r*pf[v]%M;
		e[p<<1].a[0]=1ll*l*v%M,e[p<<1|1].a[0]=1ll*r*v%M;
		e[p].cov=0; 
	}
	if(e[p].mul!=1)
	{
		int v=e[p].mul;
		MUL(e[p<<1].mul,v),MUL(e[p<<1|1].mul,v);
		MUL(e[p<<1].add,v),MUL(e[p<<1|1].add,v);
		MUL(e[p<<1].a[2],lf[v]),MUL(e[p<<1|1].a[2],lf[v]);
		MUL(e[p<<1].a[1],pf[v]),MUL(e[p<<1|1].a[1],pf[v]);
		MUL(e[p<<1].a[0],v),MUL(e[p<<1|1].a[0],v);
		e[p].mul=1;
	}
	if(e[p].add)
	{
		int v=e[p].add;
		ADD(e[p<<1].add,v);
		ADD(e[p<<1|1].add,v);
		ADD(e[p<<1].a[2],(3ll*v*e[p<<1].a[1]+3ll*pf[v]*e[p<<1].a[0]+1ll*l*lf[v])%M);
		ADD(e[p<<1|1].a[2],(3ll*v*e[p<<1|1].a[1]+3ll*pf[v]*e[p<<1|1].a[0]+1ll*r*lf[v])%M);
		ADD(e[p<<1].a[1],(2ll*v*e[p<<1].a[0]+1ll*l*pf[v])%M);
		ADD(e[p<<1|1].a[1],(2ll*v*e[p<<1|1].a[0]+1ll*r*pf[v])%M);
		ADD(e[p<<1].a[0],1ll*l*v%M);
		ADD(e[p<<1|1].a[0],1ll*r*v%M);
		e[p].add=0;
	}
}
void build(int p,int l,int r)
{
	e[p].l=l;e[p].r=r;
	for(int i=0;i<3;++i)e[p].a[i]=0;
	e[p].cov=0;e[p].mul=1;e[p].add=0;
	if(l==r)return; 
	int mid=(l+r)/2;
	build(p<<1,l,mid);
	build(p<<1|1,mid+1,r);
}
void add(int p,int ql,int qr,int v)
{
	if(ql<=e[p].l&&e[p].r<=qr)
	{
		int l=e[p].r-e[p].l+1;
		ADD(e[p].a[2],(3ll*v*e[p].a[1]+3ll*pf[v]*e[p].a[0]+1ll*l*lf[v])%M);
		ADD(e[p].a[1],(2ll*v*e[p].a[0]+1ll*l*pf[v])%M);
		ADD(e[p].a[0],1ll*l*v%M);
		ADD(e[p].add,v);
		return;
	}
	pushdown(p);
	int mid=(e[p].l+e[p].r)/2;
	if(ql<=mid)add(p<<1,ql,qr,v);
	if(qr>mid)add(p<<1|1,ql,qr,v);
	pushup(p);
}
void mul(int p,int ql,int qr,int v)
{
	if(ql<=e[p].l&&e[p].r<=qr)
	{
		int l=e[p].r-e[p].l+1;
		MUL(e[p].mul,v);
		MUL(e[p].add,v);
		MUL(e[p].a[2],lf[v]);
		MUL(e[p].a[1],pf[v]);
		MUL(e[p].a[0],v);
		return;
	}
	pushdown(p);
	int mid=(e[p].l+e[p].r)/2;
	if(ql<=mid)mul(p<<1,ql,qr,v);
	if(qr>mid)mul(p<<1|1,ql,qr,v);
	pushup(p);
}
void cov(int p,int ql,int qr,int v)
{
	if(ql<=e[p].l&&e[p].r<=qr)
	{
		int l=e[p].r-e[p].l+1;
		e[p].cov=v;e[p].mul=1;e[p].add=0;
		e[p].a[2]=1ll*l*lf[v]%M,
		e[p].a[1]=1ll*l*pf[v]%M,
		e[p].a[0]=1ll*l*v%M;
		return;
	}
	pushdown(p);
	int mid=(e[p].l+e[p].r)/2;
	if(ql<=mid)cov(p<<1,ql,qr,v);
	if(qr>mid)cov(p<<1|1,ql,qr,v);
	pushup(p);
}
int ask(int p,int ql,int qr,int op)
{
	if(ql<=e[p].l&&e[p].r<=qr)return e[p].a[op];
	pushdown(p);
	int mid=(e[p].l+e[p].r)/2,ans=0;
	if(ql<=mid)ADD(ans,ask(p<<1,ql,qr,op));
	if(qr>mid)ADD(ans,ask(p<<1|1,ql,qr,op));
	return ans;
}
int main()
{
	for(int i=1;i<M;++i)
	{
		pf[i]=(i*i)%M;
		lf[i]=(pf[i]*i)%M;
	}
	while(~scanf("%d%d",&n,&m))
	{
		if(!n&&!m)break;
		build(1,1,n);
		while(m--)
		{
			scanf("%d%d%d%d",&op,&x,&y,&v);
			if(op==1)add(1,x,y,v);
			else if(op==2)mul(1,x,y,v);
			else if(op==3)cov(1,x,y,v);
			else printf("%d\n",ask(1,x,y,v-1));
		}
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小衣同学

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

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

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

打赏作者

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

抵扣说明:

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

余额充值