一个新套路,
利用矩阵能将一些复杂的线性关系转换为一次矩阵乘法。
求解只需求区间积。
采用线段树(所以需要满足结合律)
更奇特的是你可以重载矩阵乘法时内部单个元素的乘法和加法(比如说改成取max之类的)
只要重载之后仍然满足结合律
我自己想了一个判断方法。
要A*(B*C)=(A*B)*C
令A*(B*C)=D,(A*B)*C=E
有D=E
Dij=Eij
sigma(sigma(Aik*Bkl)*Clj)=sigma(Aik*sigma(Bkl*Clj))=sigma(sigma( Aik*Bkl*Clj ))
Aik*sigma(Bkl*Clj)=sigma(Aik*Bkl*Clj)
令Aik=X,Bkl*Clj=Y
X*sigma(Y)=sigma(X*Y)
然后想一想就行了。
比如让 * 为加法, + 为取max(+为sigma内的符号)
可以做动态最大子段和问题。
sum[i] 为 以i结尾的最大子段和,ans[i] 为 i之前的最大子段和, seq[i] 为 i位置上的值。
有:
seq[i] -inf 0 sum[i-1] sum[i]
seq[i] 0 0 X ans[i-1] = ans[i]
0 0 0 0 0
然后ans[n]就是答案
动态修改只需要将第一个矩阵存在线段树里(有结合律可以乱搞)
单点修改,区间查询
另外矩阵乘法和线段树是两个卡常数重灾区,第一个矩阵有5个位置一直为0,不用存,乘的时候也不用像矩阵乘法一样三个for循环,挑会对答案造成影响的乘(比如第一行第二列一直都是-inf,干脆不算)。
给定递推式 Xi=Ai*X(i-1)+Bi
操作1:修改某对(Ai,Bi)
操作2:求Xk
#include
#include
#include
#include
#define maxn 500005
#define mod 1000000007
#define lc now<<1
#define rc now<<1|1
using namespace std;
int n,m;
struct node
{
int a,b;
node(){}
node(int a,int b):a(a),b(b){}
node operator *(const node &nxt)const
{
return node(1ll*a*nxt.a%mod,(1ll*a*nxt.b%mod+b)%mod);
}
}ele[maxn*10],tmp;
void insert(int now,int l,int r,int pos,node val)
{
if(pos>r || pos>1;
insert(lc,l,mid,pos,val);
insert(rc,mid+1,r,pos,val);
ele[now]=ele[rc]*ele[lc];
}
node Query(int now,int l,int r,int ql,int qr)
{
if(ql>r || qr>1;
return Query(rc,mid+1,r,ql,qr)*Query(lc,l,mid,ql,qr);
}
int main()
{
freopen("sequence.in","r",stdin);
freopen("sequence.out","w",stdout);
int u;
scanf("%d%d",&n,&m);
for(int i=1;i<=n*5;i++) ele[i]=node(1,0);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&tmp.a,&tmp.b);
insert(1,1,n,i,tmp);
}
char ch[10];
for(int i=1;i<=m;i++)
{
scanf("%s",ch);
if(ch[0]=='Q')
{
scanf("%d",&u);
tmp=Query(1,1,n,1,u);
printf("%d\n",(tmp.a+tmp.b)%mod);
}
else
{
scanf("%d",&u);
scanf("%d%d",&tmp.a,&tmp.b);
insert(1,1,n,u,tmp);
}
}
}
#include
#define maxn 30005
#define LL long long
#define inf (1ll<<50)
/*
calc(i+1,i+1) cc cc dp[i-1] dp[i]
0 -oo -oo dp[i-2] dp[i-1]
-oo 0 -oo dp[i-3] dp[i-2]
*/
using namespace std;
int n,q;
int w[maxn],r[maxn],c1[maxn],c2[maxn],loc[maxn],lc[maxn];
inline bool cmp1(const int &u,const int &v){ return w[u] > w[v]; }
inline bool cmp2(const int &u,const int &v){ return r[u] > r[v]; }
LL f[70000][3][3],M;
LL calc(int x,int y)
{ if(x<=0 || y<=0 || x>n || y>n) return -inf;
return 1ll * w[c1[x]] * r[c2[y]]; }
inline void mt(int x,int u=0,int v=0)
{
u = x<<1|1 , v = x<<1;
memcpy(f[x],f[0],sizeof f[0]);
for(int i=0;i<3;i++)
for(int j=0;j<3;j++) if(f[u][i][j] > -inf)
for(int k=0;k<3;k++) if(f[v][j][k] > -inf)
f[x][i][k] = max(f[x][i][k] , f[u][i][j] + f[v][j][k]);
}
void upd(int x){ for(x>>=1;x;x>>=1) mt(x); }
int main()
{
scanf("%d%d",&n,&q);
for(M=1;M