[USACO23JAN] Following Directions S 题解
因为本题时限高达
显然,每一次翻转标志操作,为了减少运算次数,我们只需更改本次操作有影响到的坐标即可。
为了便利解题,我们定义几个数组:
同时,我们定义一个点的“前驱”为可以通过一步直接走到这个坐标的坐标,“后继”为这个坐标能一步走到的下一个坐标。
第一次操作前,先预处理出
考虑每次操作后,
-
对于
f 数组:首先f_{x,y} 要从f_{x+1,y} 变为f_{x,y+1} 。其次吃饲料必须经过(x,y) 的所有奶牛的f 的值也需要相应的改变,可以通过一次 dfs 实现; -
对于
c 数组:可以看出必须经过(x+1,y) 的奶牛减少了c_{x,y} 头,必须经过(x,y+1) 的奶牛增加了c_{x,y} 头,同时它们的后继、后继的后继……的c 的值也要更新,同样可以通过 dfs 实现; -
对于答案
s :因为必须经过(x,y) 的奶牛有c_{x,y} 头,而这些奶牛坐标的f 的值都由f_{x+1,y} 变为了f_{x,y+1} ,所以s\leftarrow s+c_{x,y}(f_{x,y+1}-f_{x+1,y}) ;每次操作后输出s 即可。
放代码:
/*
ID: CrowMatrix
TASK: Following Directions
LANG: C++
*/
#include<bits/stdc++.h>
#define int long long
using namespace std;
int a[1502][1502],f[1502][1502],r[1502][1502];
void dfs(int x,int y,int u){
f[x][y]=u; r[x][y]=1;
if(x&&a[x-1][y]==-1)dfs(x-1,y,u),r[x][y]+=r[x-1][y];
if(y&&a[x][y-1]==-2)dfs(x,y-1,u),r[x][y]+=r[x][y-1];
}
void update1(int x,int y,int u){
f[x][y]=u;
if(a[x-1][y]==-1)update1(x-1,y,u);
if(a[x][y-1]==-2)update1(x,y-1,u);
}
void update2(int x,int y,int u){
r[x][y]+=u;
if(a[x][y]==-1)update2(x+1,y,u);
if(a[x][y]==-2)update2(x,y+1,u);
}
main(){
ios::sync_with_stdio(false);
int n,s=0; cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
char c; cin>>c;
if(c=='D')a[i][j]=-1;
else a[i][j]=-2;
}
cin>>a[i][n+1];
}
for(int i=1;i<=n;i++)cin>>a[n+1][i];
for(int i=1;i<=n;i++)dfs(i,n+1,a[i][n+1]),dfs(n+1,i,a[n+1][i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)s+=f[i][j];
cout<<s<<endl;
int q; cin>>q;
while(q--){
int x,y; cin>>x>>y;
if(a[x][y]==-1){
s+=(f[x][y+1]-f[x+1][y])*r[x][y];
a[x][y]=-2; update1(x,y,f[x][y+1]);
update2(x+1,y,-r[x][y]); update2(x,y+1,r[x][y]);
}
else{
s+=(f[x+1][y]-f[x][y+1])*r[x][y];
a[x][y]=-1; update1(x,y,f[x+1][y]);
update2(x,y+1,-r[x][y]); update2(x+1,y,r[x][y]);
}
cout<<s<<endl;
}
return 0;
}