原题: https://acm.ecnu.edu.cn/contest/113/problem/C/
题意:
01矩阵,
为i行和j列的0的个数,
每次操作为反转一个位置的数,求开始的Sum和每次操作后的Sum
解析:
设
为i行的0数量,
为j列的0数量,
表示ij位置是否为0,
为矩阵中0的数量
(
)
那么接下来化简题目表达式:
所以每次修改的时候找到原来的 ,再算出现在的比较计算就是答案。判断为1或0可以用set,注意每次操作后需要维护set。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=2e5+5;
const LL mod=1e9+7;
LL a[N],b[N];
struct node{
int x,y;
}e[N];
set<int>S[N];
int main(){
LL n,k,q;
scanf("%lld%lld%lld",&n,&k,&q);
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for(int i=1;i<=k;i++){
int x,y;scanf("%d%d",&x,&y);
e[i].x=x,e[i].y=y;
S[x].insert(y);
a[y]++,b[x]++;
}
for(int i=1;i<=n;i++)a[i]=n-a[i],b[i]=n-b[i];//num of 0
LL A=(n*n-k)%mod;
LL All=(2*A*A+A)%mod;
for(int i=1;i<=n;i++)All=(All+(n-2)*a[i]*a[i]%mod+(n-2)*b[i]*b[i]%mod)%mod;
printf("%lld\n",All);
while(q--){
int x,y;
scanf("%d%d",&x,&y);
LL pre=((n-2)*a[y]*a[y]%mod+(n-2)*b[x]*b[x]%mod+2*A*A%mod+A)%mod;
LL now;
if(S[x].find(y)==S[x].end()){//0->1
now=((n-2)*(a[y]-1)%mod*(a[y]-1)%mod+(n-2)*(b[x]-1)%mod*(b[x]-1)%mod+2*(A-1)*(A-1)%mod+A-1)%mod;
A--,a[y]--,b[x]--;
S[x].insert(y);
}
else{
now=((n-2)*(a[y]+1)%mod*(a[y]+1)%mod+(n-2)*(b[x]+1)%mod*(b[x]+1)%mod+2*(A+1)*(A+1)%mod+A+1)%mod;
A++,a[y]++,b[x]++;
S[x].erase(y);
}
All=((All+now-pre)%mod+mod)%mod;
printf("%lld\n",All);
}
}