hdu4578 (多标记线段树)
Posted hooying
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu4578 (多标记线段树)相关的知识,希望对你有一定的参考价值。
题意
对于一个区间有4个操作:
1.将a~b都加上c
2.将a~b都乘上c
3.将a~b都变成c
4.查询a~b的每个数的p次方的和。(p=1,2,3)
思路
平方和这样来推:((a+c)^2=a^2+2ac+c^2)
即(sum2[rt] = sum2[rt] +2*sum1[rt] * c+(r-l+1)*c*c);
立方和这样推:((a+c)^3=a^3+3a^2c+3ac^2+c^3)
即(sum3[rt]=sum3[rt]+3*sum2[rt]*c+3*sum1[rt]*c*c+(r-l+1)*c*c*c)
注意懒惰数组下传的先后顺序
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxx = 1e5+10;
const int mod = 10007;
int t[maxx<<2][4],lazy[maxx<<2][4];
void build(int l,int r,int rt)
{
lazy[rt][1]=1,lazy[rt][2]=0,lazy[rt][3]=0;
for(int i=1;i<=3;i++)t[rt][i]=0;
if(l==r)return;
int mid=(l+r)/2;
build(l,mid,rt*2);
build(mid+1,r,rt*2+1);
}
void pushdown(int l,int r,int rt)
{
if(lazy[rt][3])
{
LL c=lazy[rt][3];
t[rt*2][1]=c*l%mod;
t[rt*2+1][1]=c*r%mod;
t[rt*2][2]=c*c%mod*l%mod;
t[rt*2+1][2]=c*c%mod*r%mod;
t[rt*2][3]=c*c%mod*c%mod*l%mod;
t[rt*2+1][3]=c*c%mod*c%mod*r%mod;
lazy[rt*2][1]=lazy[rt*2+1][1]=1;
lazy[rt*2][2]=lazy[rt*2+1][2]=0;
lazy[rt*2][3]=lazy[rt*2+1][3]=c;
lazy[rt][3]=0;
}
if(lazy[rt][1]!=1)
{
LL c=lazy[rt][1];
t[rt*2][3]=t[rt*2][3]*c%mod*c%mod*c%mod;
t[rt*2+1][3]=t[rt*2+1][3]*c%mod*c%mod*c%mod;
t[rt*2][2]=t[rt*2][2]*c%mod*c%mod;
t[rt*2+1][2]=t[rt*2+1][2]*c%mod*c%mod;
t[rt*2][1]=t[rt*2][1]*c%mod;
t[rt*2+1][1]=t[rt*2+1][1]*c%mod;
lazy[rt*2][1]=lazy[rt*2][1]*c%mod;
lazy[rt*2+1][1]=lazy[rt*2+1][1]*c%mod;
lazy[rt*2][2]=lazy[rt*2][2]*c%mod;
lazy[rt*2+1][2]=lazy[rt*2+1][2]*c%mod;
lazy[rt][1]=1;
}
if(lazy[rt][2])
{
LL c=lazy[rt][2];
t[rt*2][3]=(t[rt*2][3]+3*t[rt*2][2]*c%mod+3*t[rt*2][1]*c%mod*c%mod+c*c%mod*c%mod*l%mod)%mod;
t[rt*2+1][3]=(t[rt*2+1][3]+3*t[rt*2+1][2]*c%mod+3*t[rt*2+1][1]*c%mod*c%mod+c*c%mod*c%mod*r%mod)%mod;
t[rt*2][2]=(t[rt*2][2]+2*t[rt*2][1]*c%mod+c*c%mod*l%mod)%mod;
t[rt*2+1][2]=(t[rt*2+1][2]+2*t[rt*2+1][1]*c%mod+c*c%mod*r%mod)%mod;
t[rt*2][1]=(t[rt*2][1]+c*l%mod)%mod;
t[rt*2+1][1]=(t[rt*2+1][1]+c*r%mod)%mod;
lazy[rt*2][2]=(lazy[rt*2][2]+c)%mod;
lazy[rt*2+1][2]=(lazy[rt*2+1][2]+c)%mod;
lazy[rt][2]=0;
}
}
void update(int l,int r,int p,int q,LL c,int op,int rt)
{
if(p<=l&&r<=q)
{
if(op==3)
{
t[rt][1]=c*(r-l+1)%mod;
t[rt][2]=c*c%mod*(r-l+1)%mod;
t[rt][3]=c*c%mod*c%mod*(r-l+1)%mod;
lazy[rt][1]=1,lazy[rt][2]=0;lazy[rt][3]=c;
}
else if(op==1)
{
t[rt][3]=(t[rt][3]+3*t[rt][2]*c%mod+3*t[rt][1]*c%mod*c%mod+c*c%mod*c%mod*(r-l+1)%mod)%mod;
t[rt][2]=(t[rt][2]+2*t[rt][1]*c%mod+c*c%mod*(r-l+1)%mod)%mod;
t[rt][1]=(t[rt][1]+c*(r-l+1)%mod)%mod;
lazy[rt][2]=(lazy[rt][2]+c)%mod;
}
else
{
t[rt][1]=t[rt][1]*c%mod;
t[rt][2]=t[rt][2]*c%mod*c%mod;
t[rt][3]=t[rt][3]*c%mod*c%mod*c%mod;
lazy[rt][1]=lazy[rt][1]*c%mod;
lazy[rt][2]=lazy[rt][2]*c%mod;
}
return;
}
int mid=(l+r)/2;
pushdown(mid-l+1,r-mid,rt);
if(p<=mid)update(l,mid,p,q,c,op,rt*2);
if(q>mid)update(mid+1,r,p,q,c,op,rt*2+1);
for(int i=1;i<=3;i++)t[rt][i]=(t[rt*2][i]+t[rt*2+1][i])%mod;
}
LL query(int l,int r,int p,int q,int op,int rt)
{
if(p<=l&&r<=q)return t[rt][op];
int mid=(l+r)/2;
pushdown(mid-l+1,r-mid,rt);
LL res=0;
if(p<=mid)res=(res+query(l,mid,p,q,op,rt*2))%mod;
if(q>mid)res=(res+query(mid+1,r,p,q,op,rt*2+1))%mod;
return res;
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
if(n==0&&m==0)break;
build(1,n,1);
int op,l,r,x;
while(m--)
{
scanf("%d%d%d%d",&op,&l,&r,&x);
if(op!=4)update(1,n,l,r,x,op,1);
else printf("%lld
",query(1,n,l,r,x,1));
}
}
return 0;
}
以上是关于hdu4578 (多标记线段树)的主要内容,如果未能解决你的问题,请参考以下文章
HDU - 4578 Transformation(线段树区间修改)