【题解】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;
}