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;
}
posted @ 2021-05-22 15:40  acmloser  阅读(36)  评论(0编辑  收藏  举报