因为k最大只有5,所以我建六个线段树,分别用于保存ai*i^k的值,这样就能在logn内算出值,所以此题总复杂度nlogn。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
struct Segment
{
int l;
int r;
int mid;
long long v;
bool lazy;
long long tag;
};
Segment tree[6][800000];
long long pi[6][100010];
long long si[6][100010];
long long a[100010];
long long MOD=1000000007;
int pow_mod(int a,int n)
{
if (n == 0)
return 1;
if (n == 1)
return a;
int x=pow_mod(a,n/2);
long long ans=((long long)x*x)%MOD;
if (n%2 == 1)
ans=(ans*a)%MOD;
return (int)ans;
}
void init()
{
long long i;
memset(si,0,sizeof(si));
memset(pi,0,sizeof(pi));
for(i=0;i<=100000;i++)
{
int j;
for(j=0;j<6;j++)
{
int k=j;
long long tmp=1;
while(k--)
tmp=(tmp*i)%MOD;
pi[j][i]=tmp;
if(i!=0)
si[j][i]=(si[j][i-1]+tmp)%MOD;
}
}
}
void pushdown(int w,int c)
{
int t;
int l,r;
tree[w][c].lazy=false;
l=tree[w][c<<1].l;
r=tree[w][c<<1].r;
tree[w][c<<1].v=((tree[w][c].tag*(si[w][r]-si[w][l-1]))%MOD+MOD)%MOD;
tree[w][c<<1].lazy=true;
tree[w][c<<1].tag=tree[w][c].tag;
l=tree[w][c<<1|1].l;
r=tree[w][c<<1|1].r;
tree[w][c<<1|1].v=((tree[w][c].tag*(si[w][r]-si[w][l-1]))%MOD+MOD)%MOD;
tree[w][c<<1|1].lazy=true;
tree[w][c<<1|1].tag=tree[w][c].tag;
}
void build_tree(int w,int c,int l,int r)
{
int mid;
mid=(l+r)>>1;
tree[w][c].l=l;
tree[w][c].r=r;
tree[w][c].mid=mid;
tree[w][c].lazy=false;
tree[w][c].tag=0;
if (l == r)
{
tree[w][c].v=((a[l]*pi[w][l])%MOD+MOD)%MOD;
return ;
}
build_tree(w,c<<1,l,mid);
build_tree(w,c<<1|1,mid+1,r);
tree[w][c].v=((tree[w][c<<1].v+tree[w][c<<1|1].v)%MOD+MOD)%MOD;
}
void update(int w,int c,int l,int r,int x)
{
//printf("%d %d %d %d %d\n",w,c,l,r,x);
if (tree[w][c].l == l && tree[w][c].r == r)
{
tree[w][c].lazy=true;
tree[w][c].tag=x;
tree[w][c].v=((tree[w][c].tag*(si[w][r]-si[w][l-1]))%MOD+MOD)%MOD;
return ;
}
if (tree[w][c].lazy == true)
{
pushdown(w,c);
}
if (tree[w][c].mid >= r)
{
update(w,c<<1,l,r,x);
}
else if (tree[w][c].mid < l)
{
update(w,c<<1|1,l,r,x);
}
else
{
update(w,c<<1,l,tree[w][c].mid,x);
update(w,c<<1|1,tree[w][c].mid+1,r,x);
}
tree[w][c].v=((tree[w][c<<1].v+tree[w][c<<1|1].v)%MOD+MOD)%MOD;
}
long long query(int w,int c,int l,int r)
{
if (tree[w][c].l == l && tree[w][c].r == r)
{
return (long long)tree[w][c].v;
}
if (tree[w][c].lazy == true)
{
pushdown(w,c);
}
if (tree[w][c].mid >= r)
{
return query(w,c<<1,l,r);
}
else if (tree[w][c].mid < l)
{
return query(w,c<<1|1,l,r);
}
else
{
return ((query(w,c<<1,l,tree[w][c].mid)+query(w,c<<1|1,tree[w][c].mid+1,r))%MOD+MOD)%MOD;
}
}
int getValue(int w,int l,int r,long long x,long long y)
{
return ((query(w,1,l,r)*(((x*pi[y][l-1])%MOD+MOD)%MOD))%MOD+MOD)%MOD;
}
long long getSum(int k,int l,int r)
{
long long ans;
if (k == 0)
{
ans=((getValue(0,l,r,1,0))%MOD+MOD)%MOD;
}
else if (k == 1)
{
ans=((getValue(1,l,r,1,0)-getValue(0,l,r,1,1))%MOD+MOD)%MOD;
}
else if (k == 2)
{
ans=((((getValue(2,l,r,1,0)-getValue(1,l,r,2,1))%MOD+MOD)%MOD+getValue(0,l,r,1,2))%MOD+MOD)%MOD;
}
else if (k == 3)
{
ans=((((getValue(3,l,r,1,0)-getValue(2,l,r,3,1))%MOD+MOD)%MOD+((getValue(1,l,r,3,2)-getValue(0,l,r,1,3))%MOD+MOD)%MOD )%MOD+MOD)%MOD;
}
else if (k == 4)
{
ans=((((((getValue(4,l,r,1,0)-getValue(3,l,r,4,1))%MOD+MOD)%MOD+((getValue(2,l,r,6,2)-getValue(1,l,r,4,3))%MOD+MOD)%MOD)%MOD+MOD)%MOD+getValue(0,l,r,1,4))%MOD+MOD)%MOD;
}
else if (k == 5)
{
ans=((((((getValue(5,l,r,1,0)-getValue(4,l,r,5,1))%MOD+MOD)%MOD+((getValue(3,l,r,10,2)-getValue(2,l,r,10,3))%MOD+MOD)%MOD)%MOD+MOD)%MOD+((getValue(1,l,r,5,4)-getValue(0,l,r,1,5))%MOD+MOD)%MOD)%MOD+MOD)%MOD;
}
return ans;
}
int main()
{
int n,m,t1,t2,t3,i;
char o;
init();
scanf("%d%d",&n,&m);
for (i=1; i<=n; i++)
{
scanf("%I64d",a+i);
}
for (i=0; i<6; i++)
build_tree(i,1,1,n);
while (m--)
{
scanf("%*c%c%d%d%d",&o,&t1,&t2,&t3);
if (o == '?')
{
printf("%I64d\n",(getSum(t3,t1,t2)%MOD+MOD)%MOD);
}
else if (o == '=')
{
for (i=0; i<6; i++)
{
update(i,1,t1,t2,t3);
}
}
}
return 0;
}