[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 } 
View Code

 

posted @ 2022-03-01 15:41  PYWBKTDA  阅读(60)  评论(0编辑  收藏  举报