由于BZOJ炸了,所以把题目描述也奉上

这个是BZOJ4499的改题,倒不如说更简单了

题目描述

小C最近在学习线性函数,线性函数可以表示为:$f(x) = k*x + b$。

现在小C面前有n个线性函数$f_i(x)=k_i*x+b_i$ ,他对这n个线性函数执行m次操作,每次可以:

1.M i K B 代表把第i个线性函数改为:$fi(x)=k*x+b$ 。

2.Q k 表示对1进行前k次线性映射后的结果

输入

第一行两个整数n, m (1 <= n, m <= 200,000)。

接下来n行,每行两个整数$k_i$, $b_i$。

接下来m行,每行的格式为M i K B或者Q k。

输出

对于每个Q操作,输出一行答案。

样例输入

4 5 1 3 2 4 3 1 3 4 Q 4 C 2 3 1 Q 4 C 4 1 1 Q 4

样例输出

115 124 41

提示

对于 30%的数据,n,q≤1000

对于另外 20%的数据,$a_i$=1,修改操作中 $a$=1

对于 85%数据,n,q≤ 1e5

对于 100%数据,1≤n,q≤5∗1e5,0≤$a_i,b_i$≤10

这题的思维难度不大

假设有$f_i(f_j(x))$展开

得到 $a(cx+d)+b$

那么就能轻易列出矩阵方程,

\begin{bmatrix} a & b \\ 0 & 1 \end{bmatrix} \begin{bmatrix} c & d \\ 0 & 1 \end{bmatrix}
$=$ \begin{bmatrix} ac & ad+b \\ 0 & 1 \end{bmatrix}

想要维护前k个,用线段树即可

(一个小细节:由于矩阵没有乘法交换律,依照这样的方式建线段树,查询时应查询n-k+1~n的积)

代码附上

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

inline int red(){
	int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
	for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const ll MOD = 1e9+7;
const int N = 5e5+10;

struct matrix{
	ll a[2][2];
	matrix(){memset(a,0,sizeof(a));}
	friend matrix operator *(matrix B);
};
matrix operator * (matrix A,matrix B){
	matrix C;
	for(int i=0;i<2;++i)	for(int j=0;j<2;++j)	for(int k=0;k<2;++k)
	C.a[i][j]=(C.a[i][j]+A.a[i][k]*B.a[k][j])%MOD;
	return C;
}

int a[N],b[N];
int n,q;
matrix val[N<<2];
#define ls (o<<1)
#define rs (o<<1|1)
inline void pushup(int o){
	val[o]=val[ls]*val[rs];
}
void build(int o,int l,int r){
	if(l==r){val[o].a[0][0]=a[n-l+1],val[o].a[0][1]=b[n-l+1],val[o].a[1][1]=1;return;}
	int mid=l+r>>1;
	build(ls,l,mid),build(rs,mid+1,r);
	pushup(o);
}
void modify(int o,int tl,int tr,int tar,int xa,int xb){
	if(tl==tr){val[o].a[0][0]=xa,val[o].a[0][1]=xb,val[o].a[1][1]=1;return;}
	int mid=tl+tr>>1;
	if(tar<=mid)	modify(ls,tl,mid,tar,xa,xb);
	else			modify(rs,mid+1,tr,tar,xa,xb);
	pushup(o);
}
matrix query(int o,int l,int r,int tl,int tr){
	if(l<=tl&&tr<=r)	return val[o];
	matrix ret;ret.a[0][0]=ret.a[1][1]=1;
	int mid=tl+tr>>1;
	if(l<=mid)	ret=ret*query(ls,l,r,tl,mid);
	if(r>mid)	ret=ret*query(rs,l,r,mid+1,tr);
	pushup(o);
	return ret;
}

char opt[4];

int main(){
	n=red(),q=red();
	for(int i=1;i<=n;++i)		a[i]=red(),b[i]=red();
	build(1,1,n);
	for(int i=1;i<=q;++i){
		scanf("%s",opt);
		if(opt[0]=='Q'){
			int k=red();
			matrix ret=query(1,n-k+1,n,1,n);
			ll p=(ret.a[0][0]+ret.a[0][1]+MOD)%MOD;
			printf("%lld\n",p);
		}
		else{
			int k=red(),xa=red(),xb=red();
			modify(1,1,n,n-k+1,xa,xb);
		}
	}
	return 0;
}

你以为这就A了?不,这只有85分

由于2*2矩阵常数过大,所以会有点T掉

这时我们需要手写矩阵乘来进行优化

AC代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

inline int red(){
	int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
	for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const ll MOD = 1e9+7;
const int N = 5e5+10;

struct matrix{
	ll a[2];
	matrix(){memset(a,0,sizeof(a));}
	friend matrix operator *(matrix B);
};
matrix operator * (matrix A,matrix B){
	matrix C;
	C.a[0]=A.a[0]*B.a[0]%MOD;
	C.a[1]=(A.a[0]*B.a[1]+A.a[1])%MOD;
	return C;
}

int a[N],b[N];
int n,q;
matrix val[N<<2];
#define ls (o<<1)
#define rs (o<<1|1)
inline void pushup(int o){
	val[o]=val[ls]*val[rs];
}
void build(int o,int l,int r){
	if(l==r){val[o].a[0]=a[n-l+1],val[o].a[1]=b[n-l+1];return;}
	int mid=l+r>>1;
	build(ls,l,mid),build(rs,mid+1,r);
	pushup(o);
}
void modify(int o,int tl,int tr,int tar,int xa,int xb){
	if(tl==tr){val[o].a[0]=xa,val[o].a[1]=xb;return;}
	int mid=tl+tr>>1;
	if(tar<=mid)	modify(ls,tl,mid,tar,xa,xb);
	else			modify(rs,mid+1,tr,tar,xa,xb);
	pushup(o);
}
matrix query(int o,int l,int r,int tl,int tr){
	if(l<=tl&&tr<=r)	return val[o];
	int mid=tl+tr>>1;
	pushup(o);
	if(r<=mid)		return query(ls,l,r,tl,mid);
	else if(l>mid)	return query(rs,l,r,mid+1,tr);
	else	return query(ls,l,r,tl,mid)*query(rs,l,r,mid+1,tr);
}

char opt[4];

int main(){
	n=red(),q=red();
	for(int i=1;i<=n;++i)		a[i]=red(),b[i]=red();
	build(1,1,n);
	for(int i=1;i<=q;++i){
		scanf("%s",opt);
		if(opt[0]=='Q'){
			int k=red();
			matrix ret=query(1,n-k+1,n,1,n);
			ll p=(ret.a[0]+ret.a[1]+MOD)%MOD;
			printf("%lld\n",p);
		}
		else{
			int k=red(),xa=red(),xb=red();
			modify(1,1,n,n-k+1,xa,xb);
		}
	}
	return 0;
}