题解Luogu P4121 [WC2005]双面棋盘
Posted yzhang-rp-inf
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解Luogu P4121 [WC2005]双面棋盘相关的知识,希望对你有一定的参考价值。
原题传送门
这道题肥肠毒瘤qwqwq,我被卡了qwqwq
这题的正解好像是线段树+并查集,但由于我人丑常数大被卡成了70
#include <bits/stdc++.h>
#define N 205
#define getchar nc
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
register int x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline void write(register int x)
{
if(!x)putchar('0');if(x<0)x=-x,putchar('-');
static int sta[20];register int tot=0;
while(x)sta[tot++]=x%10,x/=10;
while(tot)putchar(sta[--tot]+48);
}
int n,m;
int a[N][N];
struct node{
int le[N],ri[N],lb[N],rb[N],s0,s1;
}t[N<<2];
int fa[N<<2],tmp[N<<2];
inline int father(register int x)
{
return fa[x]==x?x:fa[x]=father(fa[x]);
}
inline void pushup(register int x)
{
t[x].s0=t[x<<1].s0+t[x<<1|1].s0;
t[x].s1=t[x<<1].s1+t[x<<1|1].s1;
memcpy(t[x].lb,t[x<<1].lb,sizeof(t[x].lb));
memcpy(t[x].rb,t[x<<1|1].rb,sizeof(t[x].rb));
for(register int i=1;i<=n<<2;++i)
fa[i]=i;
for(register int i=1;i<=n;++i)
t[x<<1|1].le[i]+=n<<1,t[x<<1|1].ri[i]+=n<<1;
for(register int i=1;i<=n;++i)
{
int xx=t[x<<1].ri[i],yy=t[x<<1|1].le[i];
if(father(xx)!=father(yy)&&t[x<<1].rb[i]==t[x<<1|1].lb[i])
{
fa[father(xx)]=father(yy);
if(t[x<<1].rb[i])
--t[x].s1;
else
--t[x].s0;
}
}
for(register int i=1;i<=n;++i)
t[x].le[i]=father(t[x<<1].le[i]),t[x].ri[i]=father(t[x<<1|1].ri[i]);
for(register int i=1;i<=n;++i)
tmp[i<<1]=t[x].le[i],tmp[(i<<1)-1]=t[x].ri[i];
sort(tmp+1,tmp+1+(n<<1));
int maxsum=unique(tmp+1,tmp+1+(n<<1))-tmp-1;
for(register int i=1;i<=n;++i)
{
t[x].le[i]=lower_bound(tmp+1,tmp+1+maxsum,t[x].le[i])-tmp;
t[x].ri[i]=lower_bound(tmp+1,tmp+1+maxsum,t[x].ri[i])-tmp;
}
for(register int i=1;i<=n;++i)
t[x<<1|1].le[i]-=n<<1,t[x<<1|1].ri[i]-=n<<1;
}
inline void build(register int x,register int l,register int r)
{
if(l==r)
{
int tot=0;
for(register int i=1;i<=n;++i)
{
if(a[i][l]!=a[i-1][l])
{
++tot;
if(a[i][l])
++t[x].s1;
else
++t[x].s0;
}
t[x].le[i]=t[x].ri[i]=tot;
t[x].lb[i]=t[x].rb[i]=a[i][l];
}
return;
}
int mid=l+r>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
pushup(x);
}
inline void change(register int x,register int l,register int r,register int pos)
{
if(l==r)
{
int tot=0;
t[x].s0=t[x].s1=0;
for(register int i=1;i<=n;++i)
{
if(a[i][l]!=a[i-1][l])
{
++tot;
if(a[i][l])
++t[x].s1;
else
++t[x].s0;
}
t[x].le[i]=t[x].ri[i]=tot;
t[x].lb[i]=t[x].rb[i]=a[i][l];
}
return;
}
int mid=l+r>>1;
if(pos<=mid)
change(x<<1,l,mid,pos);
else
change(x<<1|1,mid+1,r,pos);
pushup(x);
}
int main()
{
n=read();
for(register int i=1;i<=n;++i)
{
a[0][i]=-1;
for(register int j=1;j<=n;++j)
a[i][j]=read();
}
build(1,1,n);
m=read();
while(m--)
{
int x=read(),y=read();
a[x][y]^=1;
change(1,1,n,y);
write(t[1].s1),putchar(' '),write(t[1].s0),puts("");
}
return 0;
}
好像珂以用lct维护连通性?
以上是关于题解Luogu P4121 [WC2005]双面棋盘的主要内容,如果未能解决你的问题,请参考以下文章
题解Luogu P4121 [CQOI2016]手机号码 数位DP