Loading

【题解】CF1458E Nim Shortcuts

比 D 题的阴间欧拉路径好想多了(

首先如果 \(n=0\) 就是 nim 游戏,当且仅当 \(x=y\) 时先手必败。

我们定义先手必胜为 \(1\) ,先手必败为 \(0\) ,那么我们可以画出一个 \(0/1\) 表格,格子 \((x,y)\) 上的数表示对应状态先手的胜负。

如果 \(n=0\) ,那么就是一个除了直线 \(x-y=0\) 上为 \(0\) ,其余格子都是 \(1\) 的网格。

现在考虑 shortcut 操作。

不难发现,这等价于强行修改格子 \((x,y)\)\(0\)

根据博弈论的性质,如果当前状态可以到达必败态,则当前状态为必胜态。

这相当于将第 \(x\) 行和第 \(y\) 列全部修改为 \(1\) ,除了格子 \((x,y)\)\(0\)。然后将原来的必败直线 \(x-y=0\) 平移一个单位。

这等价于删去一行或一列。如果 \(x<y\) 则删除第 \(y\) 列,如果 \(x>y\) 则删除第 \(x\) 行,如果 \(x=y\) ,这本来就是必败态,不需要改变。

所以我们只用支持删除行/列,和原来网格中的 \((a,b)\) 在删除了这些行/列后的新位置 \((a,b)\)

这等价于查询 \(\le a/b\) 的行/列中被删除了多少个,经典二维数点问题,离线后用树状数组维护。时间复杂度 \(\mathcal{O}(N\log N)\)

需要注意一些细节。需要特判 \((a,b)\) 是 shortcut 时是必败态,当第 \(a\) 行或第 \(b\) 列被删除时是必胜态

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define pre(i,a,b) for(int i=a;i>=b;i--)
#define N 100005
using namespace std;
int n,m,o[N],b[N],T,c[N],ans[N],sz,v[N],cut = ~0;
inline void add(int x,int y){for(;x<=T;x+=x&-x)c[x]+=y;}
inline int ask(int x){int sum=0;for(;x;x-=x&-x)sum+=c[x];return sum;}
struct node{
	int op,a,b;
	bool operator<(const node o)const{
		if(a!=o.a)return a<o.a;
		return b<o.b;
	}
	bool operator<=(const node o)const{
		if(a!=o.a)return a<o.a;
		return b<=o.b;
	}
}u[N],q[N];
set<pair<int,int> >s;
void ins(int x,int y){
	int w = lower_bound(b+1,b+T+1,y) - b;
	int cur = sz - ask(w);
	if(x - y < cur){  // x - sz < y - ask()
		if(!v[w])v[w] = 1,add(w, 1);
	}
	else if(x - y > cur){
		if(x != cut) cut = x , sz++;
	}s.insert(make_pair(x,y));
}
int calc(int x,int y){
	if(s.find(make_pair(x,y)) != s.end())return 0;
	int w = upper_bound(b+1,b+T+1,y) - b - 1;
	if(v[w] && b[w] == y)return 1;
	if(cut == x)return 1;
	int cur = sz - ask(w);
	//cout<<"ss "<<x<<" "<<y<<" "<<sz<<" "<<ask(w)<<endl;
	if(x - y == cur)return 0;
	return 1;
}
int main(){
	//freopen("INPUT","r",stdin);
	scanf("%d%d",&n,&m);
	rep(i,1,n)scanf("%d%d",&u[i].a,&u[i].b),o[i]=u[i].b;
	rep(i,1,m)scanf("%d%d",&q[i].a,&q[i].b),q[i].op=i;
	sort(o+1,o+n+1);rep(i,1,n)if(i==1||o[i]!=o[i-1])b[++T]=o[i];
	sort(u+1,u+n+1);sort(q+1,q+m+1);int j=1;
	rep(i,1,m){
		while(j<=n&&u[j]<=q[i])ins(u[j].a,u[j].b),j++;
		ans[q[i].op]=calc(q[i].a,q[i].b);
	}
	rep(i,1,m)if(ans[i])puts("WIN");else puts("LOSE");
	return 0;
}
posted @ 2021-06-25 17:44  7KByte  阅读(63)  评论(0编辑  收藏  举报