标签:res tin return 线段 nfa a* 合并 search fir
Time Limit: 15000/8000 MS (Java/Others) Memory Limit: 65535/65536 K (Java/Others)
Total Submission(s): 7556 Accepted Submission(s): 1918
思路:看题意可以很明显地看出是一道线段树题,也是一道很典型的线段树
题意相当明显,就不多说了,有三种操作,这三种操作顺序不一样的话得到的结果是不一样的,对于这种多操作的问题,我们要做的事尽量将多种操作合并成一种操作。
我们可将区间中的数看成是 ax+b的形式,对于加c操作,则变成 ax+b+c(b->b+c),对于乘c操作,则变成 acx+bc,(a->ac,b->bc)对于赋值c操作,则变成c,即(a->1,x->c,b->0),则我们可以在线段数中加以下标记,a,b,x分别是以上提到的变量,sum[3],表示答案,sum[0],sum[1],sum[2]分别表示1次方和,平方和,立方和。对于更新和查询操作我们用pushdown函数向下更新。对于维护平方和还有立方和的问题,我们只要将平方,立方展开再利用更新之前的值即可维护,具体方法这里不多说了
需要说明的是:每次取修改值,如果发现当前遍历区间完全在需要更新的区间内时,更新当前顶点,同时记录本次以及以前的修改操作,此时不再往后跟新。
后面pushdown时就是从这个节点读取修改信息更新后面的点。
关键代码处给出了推到公式:
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#define maxn 100010
#define mod 10007
#define mid ((t[p].l+t[p].r)>>1)
#define ls (p<<1)
#define rs (ls|1)
using namespace std;
struct tree
{
int l,r;
int a,b,c; //a * x + b: a为乘法系数, b为需要加的值 ; c 放重置的值
int sum[3]; //三个次方的求和
}t[maxn<<2];
void pushup(int p)
{
int i;
for(i=0;i<3;i++)
t[p].sum[i]=(t[ls].sum[i]+t[rs].sum[i])%mod;
}
void pushdown(int p)
{
if(t[p].l==t[p].r)
return;
int a=t[p].a,b=t[p].b,c=t[p].c;
if(c) //需要重置
{
t[ls].a=t[rs].a=a;
t[ls].b=t[rs].b=b;
t[ls].c=t[rs].c=c;
//sum2 = k * (a * c + b)^2 //重置后每个数相同
t[ls].sum[2]=(t[ls].r-t[ls].l+1)*(a*c%mod+b)%mod*(a*c%mod+b)%mod*(a*c%mod+b)%mod;
t[ls].sum[1]=(t[ls].r-t[ls].l+1)*(a*c%mod+b)%mod*(a*c%mod+b)%mod;
t[ls].sum[0]=(t[ls].r-t[ls].l+1)*(a*c%mod+b)%mod;
t[rs].sum[2]=(t[rs].r-t[rs].l+1)*(a*c%mod+b)%mod*(a*c%mod+b)%mod*(a*c%mod+b)%mod;
t[rs].sum[1]=(t[rs].r-t[rs].l+1)*(a*c%mod+b)%mod*(a*c%mod+b)%mod;
t[rs].sum[0]=(t[rs].r-t[rs].l+1)*(a*c%mod+b)%mod;
}
else //未重置,向下更新求和
{
t[ls].a=(t[ls].a*a)%mod;
t[ls].b=(t[ls].b*a+b)%mod; //先算乘法,再算加法,即:b = b * a + b‘;
t[rs].a=(t[rs].a*a)%mod;
t[rs].b=(t[rs].b*a+b)%mod;
//(av + b)^3 = a^3*v^3 + b^3 + 3a^2 * v^2 * b + 3av * b^2 //k为区间长度
// 求和为= a^3*sum2 + K * b^3 + 3a^2 * b * sum1 + 3a*b^2 * sum0
t[ls].sum[2]=(a*a%mod*a%mod*t[ls].sum[2]%mod+3*a%mod*a%mod*b%mod*t[ls].sum[1]%mod+3*a%mod*b%mod*b%mod*t[ls].sum[0]%mod+b*b%mod*b%mod*(t[ls].r-t[ls].l+1)%mod)%mod;
//(av + b)^2=a^2*v^2 + b^2 + 2*a*b*v 求和:a^2*sum1 + b^2*k + 2ab*sum1
t[ls].sum[1]=(a*a%mod*t[ls].sum[1]%mod+b*b%mod*(t[ls].r-t[ls].l+1)%mod+2*a*b%mod*t[ls].sum[0]%mod)%mod;
//av + b 求和:a*sum0 + b*k
t[ls].sum[0]=(a*t[ls].sum[0]%mod+b*(t[ls].r-t[ls].l+1)%mod)%mod;
t[rs].sum[2]=(a*a%mod*a%mod*t[rs].sum[2]%mod+3*a%mod*a%mod*b%mod*t[rs].sum[1]%mod+3*a%mod*b%mod*b%mod*t[rs].sum[0]%mod+b*b%mod*b%mod*(t[rs].r-t[rs].l+1)%mod)%mod;
t[rs].sum[1]=(a*a%mod*t[rs].sum[1]%mod+b*b%mod*(t[rs].r-t[rs].l+1)%mod+2*a*b%mod*t[rs].sum[0]%mod)%mod;
t[rs].sum[0]=(a*t[rs].sum[0]%mod+b*(t[rs].r-t[rs].l+1)%mod)%mod;
}
t[p].b=t[p].c=0;
t[p].a=1;
}
void build(int p,int l,int r)
{
t[p].l=l,t[p].r=r;
t[p].a=1,t[p].b=t[p].c=0;
t[p].sum[0]=t[p].sum[1]=t[p].sum[2]=0; //全部初始化为0
if(l<r)
{
build(ls,l,mid);
build(rs,mid+1,r);
}
}
void change(int p,int l,int r,int val,int flag)
{
if(t[p].l==l&&t[p].r==r)
{
if(flag==0)//加val
{
t[p].b=(t[p].b+val)%mod;
//y = (x + v)^3 //x为原来的值
//y = x^3 + v^3 + 3 * x^2 * v + 3 * x * v^2;求和 = sum2 + v^3 + 3*sum1*v + 3*sum0*v^2
t[p].sum[2]=(t[p].sum[2]+3*val%mod*t[p].sum[1]%mod+3*val%mod*val%mod*t[p].sum[0]%mod+val*val%mod*val%mod*(t[p].r-t[p].l+1)%mod)%mod;
t[p].sum[1]=(t[p].sum[1]+val*val%mod*(t[p].r-t[p].l+1)%mod+2*val*t[p].sum[0]%mod)%mod;
t[p].sum[0]=(t[p].sum[0]+val*(t[p].r-t[p].l+1))%mod;
}
else if(flag==1) //乘以val
{
t[p].a=(t[p].a*val)%mod;
t[p].b=(t[p].b*val)%mod;
//y = (x * v)^3 = x^3 * v^3;求和 = v^3 * sum2
t[p].sum[2]=val*val%mod*val%mod*t[p].sum[2]%mod;
t[p].sum[1]=val*val%mod*t[p].sum[1]%mod;
t[p].sum[0]=val*t[p].sum[0]%mod;
}
else if(flag==2) //重置为val
{
t[p].a=1;
t[p].b=0;
t[p].c=val;
//y = (v)^3
t[p].sum[2]=(t[p].r-t[p].l+1)%mod*val%mod*val%mod*val%mod;
t[p].sum[1]=(t[p].r-t[p].l+1)%mod*val%mod*val%mod;
t[p].sum[0]=(t[p].r-t[p].l+1)*val%mod;
}
return;
}
pushdown(p);
if(l>mid)
change(rs,l,r,val,flag);
else if(r<=mid)
change(ls,l,r,val,flag);
else
{
change(ls,l,mid,val,flag);
change(rs,mid+1,r,val,flag);
}
pushup(p);
}
int query(int p,int l,int r,int flag)
{
if(t[p].l==l&&t[p].r==r)
return t[p].sum[flag];
pushdown(p);
if(l>mid)
return query(rs,l,r,flag);
else if(r<=mid)
return query(ls,l,r,flag);
else
{
return (query(ls,l,mid,flag)+query(rs,mid+1,r,flag))%mod;
}
}
int main()
{
// freopen("dd.txt","r",stdin);
int n,m;
while(scanf("%d%d",&n,&m)&&(n+m))
{
build(1,1,n);
int q,x,y,c;
while(m--)
{
scanf("%d%d%d%d",&q,&x,&y,&c);
if(q==4)
{
printf("%d\n",query(1,x,y,c-1));
}
else
{
change(1,x,y,c,q-1);
}
}
}
return 0;
}
30-Transformation(HDU4578)-区间线段树(复杂)
标签:res tin return 线段 nfa a* 合并 search fir
原文地址:https://www.cnblogs.com/zhumengdexiaobai/p/9543649.html