P3631 [APIO2011] 方格染色 Sol

一道推式子+带权并查集的好题

题目链接

推式子——发现结论

将红色视作1,蓝色视作0,当前位置为(x,y),则由题目可以得到:

\[a_{x,y} \oplus a_{x-1,y} \oplus a_{x,y-1} \oplus a_{x-1,y-1} = 1 \]

同理可得:

\[a_{x-2,y} \oplus a_{x-1,y} \oplus a_{x-2,y-1} \oplus a_{x-1,y-1} = 1 \]

于是有:

\[a_{x-2,y} \oplus a_{x,y} \oplus a_{x,y-1} \oplus a_{x-2,y-1} = 0 \]

推广一下,有:

\[a_{x-2k,y} \oplus a_{x,y} \oplus a_{x,y-1} \oplus a_{x-2k,y-1} = 0 \]

再次推广一下,有:

\[a_{x-2k,y} \oplus a_{x,y} \oplus a_{x,y-t} \oplus a_{x-2k,y-t} = 0 \]

同样的,有:

\[a_{x-t,y-2k} \oplus a_{x-t,y} \oplus a_{x,y-2k} \oplus a_{x,y-2k} = 0 \]

因此可以得到,如果x,y有一个是奇数,就有:

\[a_{x,y} \oplus a_{1,y} \oplus a_{x,1} \oplus a_{1,1} = 0 \]

否则,有:

\[a_{x,y} \oplus a_{1,y} \oplus a_{x,1} \oplus a_{1,1} = 1 \]

由此,我们可以发现,只用第一行,第一列的内容,就可以知道整个矩阵。

带权并查集维护

题目中的k个限制变成了对x,y的限制,可以使用并查集进行维护。

具体的,设置 \(g_i\),表示 \(val_i \oplus val_{rt}\),其中 \(rt\) 表示并查集上的最高父亲,显然的,\(g_{rt}=0\)。在并查集的find中,我们就要这样写:

int find(int x){
	if(x == fa[x]) return x;
	int tmp = fa[x];
	fa[x] = find(fa[x]);
	g[x] ^= g[tmp];
	return fa[x];
}

理解一下,\(g_x=val_{x} \oplus val_{fa}\)\(g_{fa}=val_{fa} \oplus val_{rt}\),则\(g_x \oplus g_{fa}=val_{x} \oplus val_{fa} \oplus val_{fa} \oplus val_{rt}=val_{x} \oplus val_{rt}\),可以发现是对的。

再看看计算部分。

for(int i=1;i<=k;i++){
	int u = find(x[i]),v = find(y[i] + n),num = val ^ c[i];
	if(x[i] % 2 == 0 && y[i] % 2 == 0) num ^= 1;
	if(u != v){
		fa[u] = v;
		g[u] = num ^ g[x[i]] ^ g[n + y[i]];
	}
	else if(num != g[x[i]] ^ g[n + y[i]])
		return 0;
}

先理解g[u] = num ^ g[x[i]] ^ g[n + y[i]];,首先回顾一下,我们要求\(val_{x,1} \oplus val_{1,y} \oplus num=0\),而有以下关系

  • \(g_x=val_x \oplus val_{u}\)
  • \(g_y=val_y \oplus val_{v}\)
  • \(num=val_{x} \oplus val_{y}\)
  • \(g_u=val_u \oplus val_{v}\)(这是要实现的)

因此:\(g_u=num \oplus g_{x} \oplus g_{y}=val_x \oplus val_y \oplus val_x \oplus val_u \oplus val_y \oplus val_v=val_u \oplus val_v\)

所以这是对的。

posted @ 2026-01-09 21:31  WinterXorSnow  阅读(5)  评论(0)    收藏  举报