正题
题目链接:https://www.luogu.com.cn/problem/CF1598E
题目大意
给出一个n×mn\times mn×m的网格图,开始所有都是黑色的,qqq次取反一个格子的颜色,然后求楼梯的数量。
楼梯定义为全黑色的下/右交替的格子集。
1≤n,m≤1000,1≤q≤1041\leq n,m\leq 1000,1\leq q\leq 10^41≤n,m≤1000,1≤q≤104
解题思路
注意到其实是两个斜行交错,可以考虑把坐标轴旋转45°45°45°,然后发现其实就是相邻的两行的正方形数量。
fi,jf_{i,j}fi,j表示格子(i,j)(i,j)(i,j)所在斜行再往(i,j)(i,j)(i,j)左上角的能延伸多少个黑色,然后每次O(n)O(n)O(n)暴力修改即可。
时间复杂度:O(qn)O(qn)O(qn)
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=1100;
ll n,m,q,w[N][N],a[N][N],ans;
ll calc(ll x,ll y)
{if(y<0)return 0;return min(x,y+1)+min(x,y);
}
signed main()
{scanf("%lld%lld%lld",&n,&m,&q);for(ll i=1;i<=n;i++) for(ll j=1;j<=m;j++)w[i][j]=w[i-1][j-1]+1;for(ll i=1;i<=n;i++)for(ll j=1;j<=m;j++)ans+=calc(w[i][j],w[i-1][j])+calc(w[i][j],w[i][j-1])-1;while(q--){ll x,y;scanf("%lld%lld",&x,&y);if(a[x][y]){ll dx=x,dy=y;x++;y++;while(x<=n&&y<=m&&!a[x][y]){ans-=calc(w[x][y],w[x-1][y])+calc(w[x][y],w[x][y-1])-1;ans-=calc(w[x][y],w[x+1][y]-1)+calc(w[x][y],w[x][y+1]-1);x++;y++;}x=dx;y=dy;a[x][y]^=1;while(x<=n&&y<=m&&!a[x][y])w[x][y]=w[x-1][y-1]+1,x++,y++;x=dx;y=dy;while(x<=n&&y<=m&&!a[x][y]){ans+=calc(w[x][y],w[x-1][y])+calc(w[x][y],w[x][y-1])-1;ans+=calc(w[x][y],w[x+1][y]-1)+calc(w[x][y],w[x][y+1]-1);x++;y++;}}else{ll dx=x,dy=y;while(x<=n&&y<=m&&!a[x][y]){ans-=calc(w[x][y],w[x-1][y])+calc(w[x][y],w[x][y-1])-1;ans-=calc(w[x][y],w[x+1][y]-1)+calc(w[x][y],w[x][y+1]-1);x++;y++;}x=dx;y=dy;a[x][y]^=1;w[x][y]=0;x++;y++;while(x<=n&&y<=m&&!a[x][y])w[x][y]=w[x-1][y-1]+1,x++,y++;x=dx;y=dy;x++;y++;while(x<=n&&y<=m&&!a[x][y]){ans+=calc(w[x][y],w[x-1][y])+calc(w[x][y],w[x][y-1])-1;ans+=calc(w[x][y],w[x+1][y]-1)+calc(w[x][y],w[x][y+1]-1);x++;y++;}}printf("%lld\n",ans);}
}