CF1439 E. Cheat and Win

在一个坐标系上,定义有效的点((x,y))为满足(x and y=0)的点。四相邻的点互相连边。

可以证明这是棵树,规定((0,0))为根节点。

一开始有些点是黑点,有些点是白点。两人博弈,每次可以操作一个黑点,将它和它到祖先路径上的任意点集的颜色反转。最后不能操作的输。

树的初始状态由给出(m)条路径,将(m)条路径的并染黑决定。

后手想要作弊,他在博弈前做若干次操作,每次选择一个点,将其到根路径上所有点颜色反转。最小化操作次数使得后手赢。

(mle 10^5)

(x,yin[0,10^9])


这是棵树的证明:可以发现((x,y))((x-1,y),(x,y-1))中恰好一个点连边。

核心问题:博弈必胜的判定条件。

放结论:按照深度分层,统计每层的黑点个数,如果存在一层的黑点个数为奇数,那么先手必胜。

证明考虑,当满足这个条件的时候,先手可以用一次操作将每一层的黑点个数调成偶数。到了后手时,他无论怎么操作,操作之后肯定存在一层的黑点个数为奇数。又因为必败状态每层黑点个数为(0),所以一直做下去一定是后手必输。不满足这个条件的证明类似。

另外有个阴间的考虑方法:可以将原问题拆成若干个子问题,求形如(f_x)表示只有(x)染黑的(sg)值。

假设这样考虑正确,那么原问题(sg)( xor_{xin Black} f_x)。转移可以将相同深度的点看做是等价的状态,枚举点集转移过去,得到它们的异或和,再将每种转移的情况(mex)起来。归纳一下可以发现(f_x=2^{dep_x})。最终和上面的那个结论是等价的。

接下来口胡一下为什么这样考虑是正确的。这里会用到我的一些乱搞的理论,缺乏理性证明。

现在换个问题:每次选择一个不为空的点集,将其反转。区别在于没有限制最下面那个点是黑点。如果最下面那个点是白点,操作过后后手可以重新调整会当前的局面,所以操作白点不会变得更优。

不过似乎这样调整过后黑点和白点也没什么区别;所以引入一个势函数:(phi(S)=xor_{xin Black(S)} 2^{dep_x})。显然终止时(phi(S)=0),并且它同时也是最小值。因为双方都希望获胜,不希望对方跳到比当前局面优的情况,感性理解得操作的过程中势函数一直单调不增。

这样操作黑点和白点的区别在于:操作黑点可以使势函数减少。

于是从这个角度不严谨地说明了两个问题是等价的。

后面的东西忽略上面乱讲的也没有关系。

现在改变了问题,于是不同的操作互不影响。

唯一要考虑的是原问题到了终止态的时候,如何和若干个子问题对应起对应关系呢?

原问题到终止态的时(sg=0),此时若干个子问题可能还没有结束,尽管如此它们异或和也为(0)。这说明了:如果继续做下去,那么先手必败。这就相当于是终止态了。

知道了这个结论之后,建个虚树然后随便搞一下即可。

(LCA)可以(O(lg))求,比较(dfn)序也可以通过求(LCA)做。

具体就是如果不在同一条线段上,往父亲的方向跳一大步直到到了拐点为止。


using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <cassert>
#define N 400005
#define lowbit(x) ((x)&-(x))
#define mp(x,y) (make_pair(x,y))
int n,m;
struct DOT{
	int x,y;
	int dep(){return x+y;}
	DOT fa(){
		if (x==0 && y==0) return (DOT){0,-1};
		if (x==0) return (DOT){x,y-1};
		if (y==0) return (DOT){x-1,y};
		return lowbit(x)<lowbit(y)?(DOT){x-1,y}:(DOT){x,y-1};
	}
	DOT top(){
		if (x==0 || y==0) return (DOT){0,0};
		if (lowbit(x)>lowbit(y)) return (DOT){x,y-(y&lowbit(x)-1)};
		return (DOT){x-(x&lowbit(y)-1),y};
	}
} d[N];
bool operator<(DOT a,DOT b){return a.x<b.x || a.x==b.x && a.y<b.y;}
map<DOT,int> id;
bool operator==(DOT a,DOT b){return a.x==b.x && a.y==b.y;}
bool same_line(DOT a,DOT b){return a.top()==b.top() && (a.x==b.x || a.y==b.y);}
DOT LCA(DOT a,DOT b){
	while (!same_line(a,b))
		if (a.top().dep()>b.top().dep())
			a=a.top();
		else
			b=b.top();
	return a.dep()<b.dep()?a:b;
}
bool cmpd(DOT a,DOT b){
	DOT A=a,B=b;
	while (!same_line(a,b))
		if (a.top().dep()>b.top().dep())
			a=a.top();
		else
			b=b.top();
	DOT lca=a.dep()<b.dep()?a:b;
	if (B==lca) return 0;
	if (A==lca) return 1;
	return a.y==b.y?a.x<b.x:a.y>b.y;
}
struct edge{DOT u,v;} ed[N];
struct EDGE{
	int to;
	EDGE *las;
} e[N];
int ne;
EDGE *last[N];
void link(int u,int v){
	e[ne]={v,last[u]};
	last[u]=e+ne++;
}
int build(){
	static int st[N];
	int tp=1;
	st[1]=1;
	int _m=m;
	for (int i=2;i<=m;++i){
		DOT _lca=LCA(d[i],d[st[tp]]);
		if (!id[_lca]){
			d[++_m]=_lca;
			id[_lca]=_m;
		}
		int lca=id[_lca];
		while (tp>1 && d[lca].dep()<d[st[tp-1]].dep()){
			link(st[tp-1],st[tp]);
			--tp;
		}
		if (tp && d[lca].dep()<d[st[tp]].dep()){
			link(lca,st[tp]);
			--tp;
			if (!(lca==st[tp]))
				st[++tp]=lca;
		}
		st[++tp]=i;
	}
	while (tp>1){
		link(st[tp-1],st[tp]);
		--tp;
	}
	m=_m;
	return st[1];
}
int c[N],b[N];
int q[N*2],nq;
int dep[N];
int ans[N];
void dfs(int x,int fa=0){
	dep[x]=d[x].dep();
	for (EDGE *ei=last[x];ei;ei=ei->las)
		dfs(ei->to,x),c[x]+=c[ei->to];
	if (c[x])
		q[++nq]=dep[fa]+1,q[++nq]=dep[x]+1;
	else if (b[x])
		q[++nq]=dep[x],q[++nq]=dep[x]+1;
}
int main(){
	scanf("%d",&n);
	for (int i=1;i<=n;++i){
		int x1,y1,x2,y2;
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		d[++m]={x1,y1};
		d[++m]={x2,y2};
		ed[i]={d[m-1],d[m]};
	}
	sort(d+1,d+m+1,cmpd);
	m=unique(d+1,d+m+1)-d-1;
	for (int i=1;i<=m;++i)
		id[d[i]]=i;
	int rt=build();
	for (int i=1;i<=n;++i){
		int u=id[ed[i].u],v=id[ed[i].v];
		int lca=id[LCA(d[u],d[v])];
		c[u]++,c[v]++,c[lca]-=2;
		b[lca]=1;
	}
	dfs(rt);
	sort(q+1,q+nq+1);
	int cnt=0,s=0,last[2]={-2,-2};
	for (int i=1;i<=nq;++i){
		s^=1;
		if (i==nq || q[i]!=q[i+1]){
			if (last[s]<=last[s^1])
				cnt++;
			last[s]=q[i];
		}
	}
	if (last[0]>last[1])
		cnt--;
	printf("%d
",cnt);
	return 0;
}
原文地址:https://www.cnblogs.com/jz-597/p/14002710.html