您的位置:首页 > 其它

线段树之 HDU4578Transformation

2015-08-10 14:57 288 查看
这题,整整写了一天,公式不难推,但是加乘的先后顺序影响,整整debug了一天,而且是和ac了这题的队友一起找的。。

虽说这算基础题,但写起来确实很吃力,看来水平还不够,下面的解释也写得很含糊,有时候就有种只可意会不可言传的感觉。

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <string>
#include <sstream>
using namespace std;

#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

typedef long long LL;
const double pi=4.0*atan(1.0);
const int MAXN=100005;
const int M=10007;
//	代表一次方		平方			立方
LL sumx1[MAXN<<2],sumx2[MAXN<<2],sumx3[MAXN<<2];
//	加				乘				替换	lazy标记
LL add[MAXN<<2],mul[MAXN<<2],tihuan[MAXN<<2];

void PushUp(int rt)
{
sumx1[rt]=(sumx1[rt<<1]%M+sumx1[rt<<1|1]%M)%M;
sumx2[rt]=(sumx2[rt<<1]%M+sumx2[rt<<1|1]%M)%M;
sumx3[rt]=(sumx3[rt<<1]%M+sumx3[rt<<1|1]%M)%M;
}

void PushDown(int rt,int len)
{
//必须先替换,后乘法,再加法
if(tihuan[rt]!=-1)
{
tihuan[rt<<1]=tihuan[rt]%M;
tihuan[rt<<1|1]=tihuan[rt]%M;
sumx1[rt<<1]=tihuan[rt]%M*(len-(len>>1))%M;
sumx1[rt<<1|1]=tihuan[rt]%M*(len>>1)%M;
sumx2[rt<<1]=tihuan[rt]%M*tihuan[rt]%M*(len-(len>>1))%M;
sumx2[rt<<1|1]=tihuan[rt]%M*tihuan[rt]%M*(len>>1)%M;
sumx3[rt<<1]=tihuan[rt]%M*tihuan[rt]%M*tihuan[rt]%M*(len-(len>>1))%M;
sumx3[rt<<1|1]=tihuan[rt]%M*tihuan[rt]%M*tihuan[rt]%M*(len>>1)%M;

tihuan[rt]=-1;
//这里坑了一天,首先如果替换了,那么当前的add[rt],mul[rt]里面的值不能修改!
//可能会有疑惑,不是说替换就可以去掉加法和乘法的影响吗,确实是,但是不是在这里,此时如果add[rt],mul[rt]有值就代表先发生替换,后发生加乘
//发生先发生加乘后发生替换的话,在update时候就已经将add[rt],mul[rt]清空
//这里发生替换,需要将孩子节点的add[rt],mul[rt]清空
add[rt<<1]=0;
add[rt<<1|1]=0;
mul[rt<<1]=1;
mul[rt<<1|1]=1;
}
LL x=1;
if(mul[rt]!=1)
{
LL c=mul[rt];
//这里修改add,原理同update函数里的解释
add[rt<<1]=add[rt<<1]*c%M;
add[rt<<1|1]=add[rt<<1|1]*c%M;

mul[rt<<1]=(mul[rt<<1]%M*mul[rt]%M)%M;
mul[rt<<1|1]=(mul[rt<<1|1]%M*mul[rt]%M)%M;
sumx3[rt<<1]=(sumx3[rt<<1]%M*c%M*c%M*c%M)%M;
sumx2[rt<<1]=(sumx2[rt<<1]%M*c%M*c%M)%M;
sumx1[rt<<1]=(sumx1[rt<<1]%M*c%M)%M;
sumx3[rt<<1|1]=(sumx3[rt<<1|1]%M*c%M*c%M*c%M)%M;
sumx2[rt<<1|1]=(sumx2[rt<<1|1]%M*c%M*c%M)%M;
sumx1[rt<<1|1]=(sumx1[rt<<1|1]%M*c%M)%M;
mul[rt]=1;
}
if(add[rt])
{
LL c=add[rt]%M;
add[rt<<1]=(add[rt<<1]+c)%M;
add[rt<<1|1]=(add[rt<<1|1]+c)%M;
sumx3[rt<<1]=(sumx3[rt<<1]+(3*c%M*c%M*sumx1[rt<<1]%M+3*c*sumx2[rt<<1]%M)%M+(c%M*c%M*c%M)%M*(len-(len>>1)))%M;
sumx2[rt<<1]=(sumx2[rt<<1]+2*c%M*sumx1[rt<<1]%M+(c%M*c%M)*(len-(len>>1))%M)%M;
sumx1[rt<<1]=(sumx1[rt<<1]+c*(len-(len>>1))%M)%M;
sumx3[rt<<1|1]=(sumx3[rt<<1|1]+(3*c%M*c%M*sumx1[rt<<1|1]%M+3*c*sumx2[rt<<1|1]%M)+(c*c*c)*(len>>1))%M;
sumx2[rt<<1|1]=(sumx2[rt<<1|1]+(2*c%M*sumx1[rt<<1|1])+(c*c)*(len>>1)%M)%M;
sumx1[rt<<1|1]=(sumx1[rt<<1|1]+c*(len>>1)%M)%M;
add[rt]=0;
}

}
void build(int l,int r,int rt)
{
add[rt]=0;
mul[rt]=1;
tihuan[rt]=-1;
if(l==r)
{
sumx1[rt]=0;
sumx2[rt]=0;
sumx3[rt]=0;
return ;
}
int m=(l+r)>>1;
build(lson);
build(rson);
PushUp(rt);
}
void update(int kind,int L,int R,LL c,int l,int r,int rt)
{
if(L<=l &&r<=R)
{
if(kind==1)//加法
{
//跟平时遇到的累加一样
add[rt]=(add[rt]+c)%M;//lazy标记add累加

sumx3[rt]=(sumx3[rt]+(3*c%M*c%M*sumx1[rt]%M+3*c*sumx2[rt]%M)+c*c%M*c%M*(r-l+1))%M;
sumx2[rt]=(sumx2[rt]+(2*c%M*sumx1[rt])+(c*c%M)*(r-l+1)%M)%M;
sumx1[rt]=(sumx1[rt]+c*(r-l+1)%M)%M;
return ;
}
if(kind==2)//乘法
{
//这里是重点,首先因为加法和乘法同时存在,所以两者之间的顺序关系会影响到结果
//当前是乘法,那么add标记里的值也要乘上该数字,否则我们必须要考虑加法和乘法的顺序,这样会相当复杂
//比如(x+3)*4
//先前add[rt]=3,此时我们进行*4,如果单单mul[rt]*=4,那么更新孩子节点时,就会发现不对了,更新成了x*4+3
//实际上(x+3)*4=4*x+12
//好吧,我也讲不清楚了
add[rt]=add[rt]*c%M;
mul[rt]=(mul[rt]*c)%M;
sumx3[rt]=(sumx3[rt]*c%M*c%M*c%M)%M;
sumx2[rt]=(sumx2[rt]*c%M*c%M)%M;
sumx1[rt]=(sumx1[rt]*c%M)%M;
return ;

}
if(kind==3)//替换
{
//替换的话,加法和乘法的标记都可以清空了
tihuan[rt]=c%M;
sumx1[rt]=c%M*(r-l+1)%M;
sumx2[rt]=c%M*c%M*(r-l+1)%M;
sumx3[rt]=c%M*c%M*c%M*(r-l+1)%M;
add[rt]=0;
mul[rt]=1;
return ;

}
}

PushDown(rt,r-l+1);

int m=(l+r)>>1;

if(L<=m)
update(kind,L,R,c,lson);
if(m<R)
update(kind,L,R,c,rson);

PushUp(rt);
}
LL ans;
void query(int L, int R,int kind,int l,int r,int rt)
{
if(L<=l &&r<=R)
{
if(kind==1)
ans=(ans+sumx1[rt]%M)%M;
else if(kind==2)
ans=(ans+sumx2[rt]%M)%M;
else if(kind==3)
ans=(ans+sumx3[rt]%M)%M;
return;
}
PushDown(rt,r-l+1);

int m=(l+r)>>1;

if(L<=m)
query(L,R,kind,lson);
if(m<R)
query(L,R,kind,rson);
}
int main()
{
int n,m;
int i,j,k;
int x,y,z;
int t;

while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0)
return 0;

build(1,n,1);
int cnt=0;
while(m--)
{
scanf("%d%d%d%d",&t,&x,&y,&z);
if(t!=4)
update(t,x,y,(LL)z,1,n,1);
else
{
ans=0;
query(x,y,z,1,n,1);
ans%=M;
printf("%I64d\n",ans);
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: