链接:点击打开链接
题意:给定一个n*m的矩阵,每个点有一个权值,现在有两种操作,一种是将其中任何一个元素改成1~c中的任意值,另一种是输出权值u按十字计数的种数(具体看样例)
代码:
#include <queue>
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
int n,m;
int num[105],s[105][105];
int le[105][105],re[105][105],up[105][105],dw[105][105];
void cal(int x,int y,int id){
int i;
if(id==1){
for(i=x+1;i<=n;i++){
if(s[i][y]==s[x][y])
dw[x][y]++;
else
break;
}
}
else if(id==2){
for(i=x-1;i>=1;i--){
if(s[i][y]==s[x][y])
up[x][y]++;
else
break;
}
}
else if(id==3){
for(i=y-1;i>=1;i--){
if(s[x][i]==s[x][y])
le[x][y]++;
else
break;
}
}
else{
for(i=y+1;i<=m;i++){
if(s[x][i]==s[x][y])
re[x][y]++;
else
break;
}
}
}
void update(int x,int y,int op){ //每个点分三种情况讨论一下即可
int i;
if(s[x][y]==op)
return;
for(i=1;i<=x-1;i++){
if(dw[i][y]<x-i-1)
continue;
else if(dw[i][y]==x-i-1){
if(s[i][y]==op){
dw[i][y]++;
if(x+1<=n&&s[x+1][y]==s[i][y])
dw[i][y]+=(dw[x+1][y]+1);
}
}
else
dw[i][y]=x-i-1;
}
for(i=n;i>=x+1;i--){
if(up[i][y]<i-x-1)
continue;
else if(up[i][y]==i-x-1){
if(s[i][y]==op){
up[i][y]++;
if(x-1>=1&&s[x-1][y]==s[i][y])
up[i][y]+=(up[x-1][y]+1);
}
}
else
up[i][y]=i-x-1;
}
for(i=1;i<=y-1;i++){
if(re[x][i]<y-i-1)
continue;
else if(re[x][i]==y-i-1){
if(s[x][i]==op){
re[x][i]++;
if(y+1<=m&&s[x][y+1]==s[x][i])
re[x][i]+=(re[x][y+1]+1);
}
}
else
re[x][i]=y-i-1;
}
for(i=m;i>=y+1;i--){
if(le[x][i]<i-y-1)
continue;
else if(le[x][i]==i-y-1){
if(s[x][i]==op){
le[x][i]++;
if(y-1>=1&&s[x][y-1]==s[x][i])
le[x][i]+=(le[x][y-1]+1);
}
}
else
le[x][i]=i-y-1;
}
s[x][y]=op;
up[x][y]=dw[x][y]=le[x][y]=re[x][y]=0;
for(i=1;i<=4;i++)
cal(x,y,i);
}
int main(){
char ch;
int c,q,i,j,u,v,id,op;
while(scanf("%d%d%d%d",&n,&m,&c,&q)!=EOF){
for(i=1;i<=n;i++) //直接维护每个点向四个方向的连续长度
for(j=1;j<=m;j++) //当改任何一个值时,可以每个点直接O(1)
scanf("%d",&s[i][j]); //进行更改,因此复杂度就为O(Q*2*(n+m))
memset(le,0,sizeof(le));
memset(re,0,sizeof(re));
memset(up,0,sizeof(up));
memset(dw,0,sizeof(dw));
memset(num,0,sizeof(num));
for(i=1;i<=n;i++){ //直接维护出每个点四个方向的值
for(j=1;j<=m;j++){
for(id=1;id<=4;id++)
cal(i,j,id);
}
}
for(i=1;i<=n;i++)
for(j=1;j<=m;j++) //四个方向最小值即为每个点的个数
num[s[i][j]]+=min(min(up[i][j],dw[i][j]),min(le[i][j],re[i][j]));
while(q--){
cin>>ch;
if(ch=='Q'){
scanf("%d",&u);
printf("%d\n",num[u]);
}
else{
scanf("%d%d%d",&u,&v,&op);
for(j=1;j<=m;j++) //询问时可以先将原来的值都减掉
num[s[u][j]]-=min(min(up[u][j],dw[u][j]),min(le[u][j],re[u][j]));
for(i=1;i<=n;i++){ //当更新后再重新加回来
if(i==u)
continue;
num[s[i][v]]-=min(min(up[i][v],dw[i][v]),min(le[i][v],re[i][v]));
}
update(u,v,op);
for(j=1;j<=m;j++)
num[s[u][j]]+=min(min(up[u][j],dw[u][j]),min(le[u][j],re[u][j]));
for(i=1;i<=n;i++){
if(i==u)
continue;
num[s[i][v]]+=min(min(up[i][v],dw[i][v]),min(le[i][v],re[i][v]));
}
}
}
}
return 0;
}