线段树分治模板题。
Part.1
Q:如果没有修改,我们怎么做?
A:用并查集维护连通性。
直接扫一遍,我们加进来一个数,就先令答案++,看一下四个方向,如果某个方向与当前点不在同一个连通块中,那么就合并并查集,令答案–。
Part.2
有修改?并查集不支持删除?怎么办?乱搞
这里我们可以请出我们解决这类问题的神器,线段树分治。(没有学过的请左转【模板】线段树分治)
我们知道每个位置在时间轴上有时是0,有时是1,那么对应的就是一段一段的区间,由线段树的性质,每个区间都可以拆成log个小区间,我们只用先在那些位置挂上修改操作,再跑一遍dfs,走到对应点时修改,回退时再撤销即可,走到叶节点时再输出答案即可。
总时间复杂度$O(mlog(n^2+m))$
具体实现可以看代码。
#define Id(x,y) ((x-1)*n+y)
using namespace std;
typedef pair<int,int> pii;
const int maxn=205;
const int dx[]={1,0,-1,0};
const int dy[]={0,1,0,-1};
int mp[maxn][maxn],fa[maxn*maxn],dep[maxn*maxn],n,m,ans[2],pre[maxn][maxn],cnt;
struct Query
{
int l,r,val,x,y;
}q[maxn*maxn*2];
stack<pii> st;
vector<int> wife[maxn*maxn*4];
template<typename T>
inline void read(T &x)
{
char c;int f=1;
while(!isdigit(c=getchar())) (c=='-')&&(f=-1);
x=c^48;
while(isdigit(c=getchar())) x=x*10+(c^48);
x*=f;
}
void modify(int u,int l,int r,int x,int y,int id)
{
if(x<=l&&r<=y) return void(wife[u].push_back(id));
int mid=(l+r)>>1;
if(x<=mid) modify(u<<1,l,mid,x,y,id);
if(y>mid) modify(u<<1|1,mid+1,r,x,y,id);
}
inline int findf(int x)
{
while(fa[x]!=x) x=fa[x];
return x;
}
void merge(int u,int v)
{
if(u==v) return;
if(dep[u]>dep[v]) swap(u,v);
st.push(make_pair(u,dep[u]==dep[v]));
fa[u]=v;dep[v]+=(dep[u]==dep[v]);
}
void solve(int u,int l,int r)
{
int siz=st.size(),ans0=ans[0],ans1=ans[1];
for(const auto &i:wife[u])
{
ans[q[i].val]++;
mp[q[i].x][q[i].y]=q[i].val;
for(int j=0,pref=0;j<4;++j)
{
int tx=q[i].x+dx[j],ty=q[i].y+dy[j];
if(tx<=0||ty<=0||tx>n||ty>n) continue;
if(mp[q[i].x][q[i].y]==mp[tx][ty])
{
int x=findf(Id(q[i].x,q[i].y)),y=findf(Id(tx,ty));
if(x==y) continue;
--ans[q[i].val];merge(x,y);
}
}
}
if(l==r) printf("%d %d\n",ans[1],ans[0]);
else
{
int mid=(l+r)>>1;
solve(u<<1,l,mid);solve(u<<1|1,mid+1,r);
}
for(const auto &i:wife[u])
mp[q[i].x][q[i].y]=-1;
ans[0]=ans0;ans[1]=ans1;
while(st.size()>siz)
{
int x=st.top().first;
dep[fa[x]]-=st.top().second;
fa[x]=x;st.pop();
}
}
int main()
{
int x,y;
read(n);
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
read(mp[i][j]);
read(m);
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
q[Id(i,j)]=(Query){1,m,mp[i][j],i,j},pre[i][j]=Id(i,j);
for(int i=1;i<=n*n;++i) fa[i]=i;
cnt=n*n;
for(int i=1;i<=m;++i)
{
read(x);read(y);
q[pre[x][y]].r=i-1;
q[++cnt]=(Query){i,m,mp[x][y]^=1,x,y};
pre[x][y]=cnt;
}
for(int i=1;i<=cnt;++i)
if(q[i].l<=q[i].r) modify(1,1,m,q[i].l,q[i].r,i);
memset(mp,-1,sizeof(mp));
solve(1,1,m);
return 0,qwq;
}