[luogu5897]wombats
维护一棵线段树,区间$[l,r]$上维护一个$C\times C$的矩阵,表示对应的最短路
考虑矩阵$A$和$B$合并,即$merge(A,B)_{i,j}=\min_{1\le k\le C}A_{i,k}+B_{k,j}$
记$pos_{i,j}$为取到最小值的$k$,不难证明其具有单调性(对$i$和$j$均单调不降)
根据单调性,有$pos_{i,j-1}\le pos_{i,j}\le pos_{i+1,j}$,进而每一条对角线均可$o(C)$求出
在此基础上,初始化$o(RC^{2}),$单次修改$o(C^{2}\log R),$单次询问$o(1)$,均可通过
但是,注意到空间复杂度为$o(RC^{2})$(还有线段树的4倍常数),无法通过
设置阈值$K$,并对线段树上长度$\le K$的区间暴力计算(而不是递归)
此时,单次修改升为$o(C^{2}\log R+C^{2}K),$空间复杂度降为$o(\frac{RC^{2}}{K})$,取$K=10$即可通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 5005 4 #define M 205 5 #define K 10 6 #define T 2005 7 #define L (k<<1) 8 #define R (L+1) 9 #define mid (l+r>>1) 10 #define Val(x,y,z) a.a[x][y]+b.a[y][z] 11 struct mat{ 12 int a[M][M]; 13 }f[T]; 14 int n,C,m,p,x,y,z,H[N][M],V[N][M],sum[M],pos[M][M]; 15 mat Set(int k){ 16 mat a; 17 for(int i=1;i<C;i++)sum[i]=sum[i-1]+H[k][i]; 18 for(int i=1;i<=C;i++) 19 for(int j=1;j<=i;j++)a.a[i][j]=a.a[j][i]=sum[i-1]-sum[j-1]; 20 for(int i=1;i<=C;i++) 21 for(int j=1;j<=C;j++)a.a[i][j]+=V[k][j]; 22 return a; 23 } 24 mat mul(mat a,mat b){ 25 mat ans; 26 for(int k=1-C;k<C;k++) 27 for(int i=1;i<=C;i++){ 28 int j=i+k; 29 if ((j<1)||(j>C))continue; 30 int l=1,r=C; 31 if (j>1)l=pos[i][j-1]; 32 if (i<C)r=pos[i+1][j]; 33 pos[i][j]=l; 34 for(int t=l+1;t<=r;t++) 35 if (Val(i,t,j)<Val(i,pos[i][j],j))pos[i][j]=t; 36 ans.a[i][j]=Val(i,pos[i][j],j); 37 } 38 return ans; 39 } 40 mat build(int l,int r){ 41 mat a=Set(l); 42 for(int i=l+1;i<=r;i++)a=mul(a,Set(i)); 43 return a; 44 } 45 void build(int k,int l,int r){ 46 if (r-l+1<=K){ 47 f[k]=build(l,r); 48 return; 49 } 50 build(L,l,mid),build(R,mid+1,r); 51 f[k]=mul(f[L],f[R]); 52 } 53 void update(int k,int l,int r,int x){ 54 if (r-l+1<=K){ 55 f[k]=build(l,r); 56 return; 57 } 58 if (x<=mid)update(L,l,mid,x); 59 else update(R,mid+1,r,x); 60 f[k]=mul(f[L],f[R]); 61 } 62 int main(){ 63 scanf("%d%d",&n,&C); 64 for(int i=1;i<=n;i++) 65 for(int j=1;j<C;j++)scanf("%d",&H[i][j]); 66 for(int i=1;i<n;i++) 67 for(int j=1;j<=C;j++)scanf("%d",&V[i][j]); 68 build(1,1,n-1); 69 scanf("%d",&m); 70 for(int i=1;i<=m;i++){ 71 scanf("%d%d%d",&p,&x,&y); 72 x++,y++; 73 if (p==1){ 74 scanf("%d",&H[x][y]); 75 update(1,1,n-1,x); 76 } 77 if (p==2){ 78 scanf("%d",&V[x][y]); 79 update(1,1,n-1,x); 80 } 81 if (p==3){ 82 for(int j=1;j<C;j++)sum[j]=sum[j-1]+H[n][j]; 83 int ans=f[1].a[x][y]; 84 for(int j=1;j<y;j++)ans=min(ans,f[1].a[x][j]+sum[y-1]-sum[j-1]); 85 for(int j=y;j<=C;j++)ans=min(ans,f[1].a[x][j]+sum[j-1]-sum[y-1]); 86 printf("%d\n",ans); 87 } 88 } 89 return 0; 90 }