Transformation HDU - 4578
原题链接
考察:线段树
思路:
维护序列的扩展版.
1操作 : 区间修改
2操作 : 区间修改
3操作 : 类似线段树染色的区间修改.
4操作 : 区间查询.
对于操作1,2,3考虑每个操作如何影响需要维护的平方和,立方和.
原平方和: a2+b2+c2+...
操作1后: (a+x)2+(b+x)2+(c+x)2+...(n个)
= a2+2*x*a+x2+b2+2*x*b+x2+...
= (a2+b2+c2+...)+2*x*(a+b+c+...)+n*x2
= (原平方和)+2*x*(原和)+n*x2
同理立方和的影响也可以通过数学公式求出(多动笔!!!)
操作2,3 : 这个应该很容易推,不写了.
考虑如何维护后,接下来考虑每个操作如何push_up,push_down.
这里直接看这位大佬的博客吧 GO!!!,我直接讲要注意几个点:
1.不要写成染色的push_up,如果我们把[l,r]的3懒标记下传,左右相对就不要再传上来了!!!
2.下传到子节点的时候,父节点的mul与add懒标记不能去掉,这里只能去除掉子节点的mul与add懒标记.父节点的mul,add懒标记我们已经在染色函数里去除了.
3.更新子节点的sum_1时,不要再用mul*add了,add在父节点那里已经更新过了
4.这里的3操作,如果像之前一样把-1定义为多种颜色,0为无染色.这样push_up函数里,判断有无3的懒标记需要再特判0,因此把多种颜色也定义为0.
5.query操作,直接不考虑染色的懒标记,这样更容易写...否则将父节点的c保持不变,下次push_down导致答案错误,因为push_up是不会更新父节点的c的.
Code:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int Mod = 10007,N=100010;
struct Node{
int l,r,c;
LL sum_1,sum_2,sum_3,add,mul;
}tr[N<<2];
int n,m;
int get(int u)
{
return tr[u].r-tr[u].l+1;
}
int qsm(int a,int k,int q)
{
int res = 1;
while(k)
{
if(k&1) res = (LL)res*a%q;
a = (LL)a*a%q;
k>>=1;
}
return res;
}
void get_sum(Node& u,int op,LL mul,LL add)
{
int len = u.r-u.l+1;
if(op==1)
{//不需要再让add*mul了,因为形式都是a*mul+add
u.sum_1 = (LL)u.sum_1*mul%Mod+(LL)add*len%Mod;
u.sum_1 %=Mod;
}
if(op==2)
{
u.sum_2 = (LL)u.sum_2*qsm(mul,2,Mod)%Mod+(LL)2*mul*add%Mod*u.sum_1%Mod+(LL)len*add*add%Mod;
u.sum_2 %=Mod;
}
if(op==3)
{
u.sum_3 = (LL)u.sum_3*qsm(mul,3,Mod)%Mod+(LL)3*mul*add%Mod*mul%Mod*u.sum_2%Mod+(LL)3*mul*add%Mod*add%Mod*u.sum_1%Mod+len*qsm(add,3,Mod)%Mod;
u.sum_3 %=Mod;
}
}
void build(int u,int l,int r)
{
tr[u] = {l,r,0,0,0,0,0,1};
if(l==r) return;
int mid = l+r>>1;
build(u<<1,l,mid); build(u<<1|1,mid+1,r);
}
void push_down(int u)
{
if(tr[u].c)
{
LL c = tr[u].c;
tr[u<<1].c = tr[u<<1|1].c = c;
tr[u<<1].sum_1 = c*get(u<<1)%Mod;
tr[u<<1].sum_2 = c*c%Mod*get(u<<1)%Mod;
tr[u<<1].sum_3 = c*c%Mod*c%Mod*get(u<<1)%Mod;
tr[u<<1|1].sum_1 = c*get(u<<1|1)%Mod;
tr[u<<1|1].sum_2 = c*c%Mod*get(u<<1|1)%Mod;
tr[u<<1|1].sum_3 = c*c%Mod*c%Mod*get(u<<1|1)%Mod;
// tr[u].add =0,tr[u].mul =1;
tr[u<<1].add = 0,tr[u<<1].mul = 1;
tr[u<<1|1].add = 0,tr[u<<1|1].mul = 1;
}
LL add = tr[u].add,mul = tr[u].mul;
get_sum(tr[u<<1],3,mul,add);
get_sum(tr[u<<1|1],3,mul,add);
get_sum(tr[u<<1],2,mul,add);
get_sum(tr[u<<1|1],2,mul,add);
get_sum(tr[u<<1],1,mul,add);
get_sum(tr[u<<1|1],1,mul,add);
tr[u<<1].mul = tr[u<<1].mul*mul%Mod,tr[u<<1].add = ((LL)tr[u<<1].add*mul%Mod+add)%Mod;
tr[u<<1|1].mul = tr[u<<1|1].mul*mul%Mod,tr[u<<1|1].add = ((LL)tr[u<<1|1].add*mul%Mod+add)%Mod;
tr[u].add = 0,tr[u].mul = 1,tr[u].c = 0;
}
void push_up(int u)
{
tr[u].sum_1 = (tr[u<<1].sum_1+tr[u<<1|1].sum_1)%Mod;
tr[u].sum_2 = (tr[u<<1].sum_2+tr[u<<1|1].sum_2)%Mod;
tr[u].sum_3 = (tr[u<<1].sum_3+tr[u<<1|1].sum_3)%Mod;
// if(tr[u<<1].c!=tr[u<<1|1].c) tr[u].c = 0;
// else tr[u].c = tr[u<<1].c;
}
void modify(int u,int l,int r,int mul,int add)
{
if(tr[u].l>=l&&tr[u].r<=r)
{
tr[u].sum_3 = (LL)tr[u].sum_3*qsm(mul,3,Mod)%Mod+(LL)3*add*mul%Mod*mul%Mod*tr[u].sum_2%Mod+(LL)3*mul*add%Mod*add%Mod*tr[u].sum_1%Mod+get(u)*qsm(add,3,Mod)%Mod;
tr[u].sum_3 %=Mod;
tr[u].sum_2 = (LL)tr[u].sum_2*qsm(mul,2,Mod)%Mod+(LL)2*mul*add%Mod*tr[u].sum_1%Mod+(LL)get(u)*add*add%Mod;
tr[u].sum_2 %=Mod;
tr[u].sum_1 = (LL)tr[u].sum_1*mul%Mod+(LL)mul*add*get(u)%Mod;
tr[u].sum_1 %=Mod;
tr[u].add=tr[u].add*mul%Mod+add,tr[u].add%=Mod;
tr[u].mul*=mul,tr[u].mul%=Mod;
return;
}
push_down(u);
int mid = tr[u].l+tr[u].r>>1;
if(l<=mid) modify(u<<1,l,r,mul,add);
if(mid<r) modify(u<<1|1,l,r,mul,add);
push_up(u);
}
void Color(int u,int l,int r,int c)
{
if(tr[u].l>=l&&tr[u].r<=r)
{
tr[u].c = c;
tr[u].sum_1 = (LL)c*get(u)%Mod;
tr[u].sum_2 = (LL)c*c%Mod*get(u)%Mod;
tr[u].sum_3 = (LL)c*c%Mod*c%Mod*get(u)%Mod;
tr[u].add =0,tr[u].mul =1;
return;
}
push_down(u);
int mid = tr[u].l+tr[u].r>>1;
if(l<=mid) Color(u<<1,l,r,c);
if(mid<r) Color(u<<1|1,l,r,c);
push_up(u);
}
int GetRe(int op,int u)
{
if(op==1) return tr[u].sum_1;
if(op==2) return tr[u].sum_2;
if(op==3) return tr[u].sum_3;
}
LL query(int u,int l,int r,int op)
{
if(tr[u].l>=l&&tr[u].r<=r) return GetRe(op,u);
push_down(u);
int mid = tr[u].l+tr[u].r>>1,res = 0;
if(l<=mid) res += query(u<<1,l,r,op);
res%=Mod;
if(mid<r) res+= query(u<<1|1,l,r,op);
res%=Mod;
return res;
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF&&(n+m))
{
build(1,1,n);
while(m--)
{
int op,l,r,x;
scanf("%d%d%d%d",&op,&l,&r,&x);
if(op==1) modify(1,l,r,1,x);
if(op==2) modify(1,l,r,x,0);
if(op==3) Color(1,l,r,x);
if(op==4) printf("%lld\n",query(1,l,r,x));
}
}
return 0;
}