思路:
解决这道题需要用到线段树,通俗的说,每个父节点就是两个字结点上的函数套起来,而题目中的要求可看做单点修改和区间查询
于是问题来了,怎么建树呢。。拿出纸和笔,我们来找规律:
f1(x) = k[1]*x+b[1]
f2(f1(x)) = k[2]*(k[1]*x+b[1])+b[2] = k[1]*k[2]*x+k[2]*b[1]+b[2]
f3(f2(f1(x))) = k[3]*( k[2]*(k[1]*x+b[1])+b[2]) = k[1]*k[2]*k[3]*x+k[2]*k[3]*b[1]+k[3]*b[2]+b[3]
跟着式子走,我们发现各个复合函数中的k和b其实是有一定规律的,因此建立线段树时,我们需要定义四个变量l,r,mul,sum,分别代表区间临界 和 线段树上复合函数的k和b。
可以得到父节点和子节点的关系(ans代表父节点,l,r分别代表左孩子和右孩子)
ans.l=x.l;ans.r=y.r;
ans.mul=x.mul*y.mul%mod;
ans.sum=(x.sum*y.mul%mod+y.sum)%mod;
#include<iostream> #include<cstdio> using namespace std; const int mod=1e9+7; const int N=200005; int n,m,K[N],b[N]; struct node { int l,r; long long mul,sum; }t[N<<2]; inline int read() { int a=0,f=1; char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();} return a*f; } inline node Unite(node x,node y) { node ans; ans.l=x.l; ans.r=y.r; ans.mul=x.mul*y.mul%mod; ans.sum=(x.sum*y.mul%mod+y.sum)%mod; return ans; } inline void pushup(int k) { t[k]=Unite(t[k<<1],t[k<<1|1]); } void build(int k,int x,int y) { if (x==y) { t[k].l=t[k].r=x; t[k].sum=b[x]; t[k].mul=K[x]; return; } int mid=x+y>>1; build(k<<1,x,mid); build(k<<1|1,mid+1,y); pushup(k); } void modify(int k,int x,int K,int B) { if (t[k].l==t[k].r) { t[k].sum=B; t[k].mul=K; return; } int mid=t[k].l+t[k].r>>1; if (x<=mid) modify(k<<1,x,K,B); else modify(k<<1|1,x,K,B); pushup(k); } node query(int k,int x,int y) { if (t[k].l==x&&t[k].r==y) return t[k]; int mid=t[k].l+t[k].r>>1; if (y<=mid) return query(k<<1,x,y); else if (x>mid) return query(k<<1|1,x,y); else return Unite(query(k<<1,x,mid),query(k<<1|1,mid+1,y)); } int main() { freopen("fx.in","r",stdin); freopen("fx.out","w",stdout); n=read(); m=read(); for (int i=1;i<=n;i++) K[i]=read(),b[i]=read(); build(1,1,n); for (int i=1;i<=m;i++) { char opt[5]; scanf("%s",opt); if (opt[0]=='M') { int x=read(),k=read(),b=read(); modify(1,x,k,b); } else { int l=read(),r=read(),x=read(); node ans=query(1,l,r); printf("%I64d ",(ans.mul*x%mod+ans.sum)%mod); } } fclose(stdin); fclose(stdout); return 0; }