两堆石子的nim游戏,另外定义了(n)个点((x_i,y_i))为必败点。
一堆询问问((x,y))是否必胜。
(n,mle 10^5)
先判掉刚好在必败点的情况。
考虑转移式,((x,y))必胜当且仅当((x,y))正下或正左有必败点。
如果能求出每行每列的第一个必败点就好做了。
枚举行,算出在这行的被硬点的必败点的最小值,以及(mex({x|x列上方存在必败点}))。两者取(min),就是这行的第一个必败点。在这个必败点之后,除了被钦定的必败点之外都是必胜点。
由于行数比较多,对于空行(没有操作和询问的行)之间的必败点随便处理一下(就是移动(mex))。
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#define N 100005
#define ll long long
#define INF 1000000001ll
int n,m;
set<ll> fail;
map<int,vector<int> > v;
int q[N];
set<int> c;
int ans[N];
int main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;++i){
int x,y;
scanf("%d%d",&x,&y);
fail.insert(x*INF+y);
v[x].push_back(y);
}
fail.insert(0);
v[0].push_back(0);
for (int i=1;i<=m;++i){
int x,y;
scanf("%d%d",&x,&y);
if (fail.find(x*INF+y)!=fail.end())
ans[i]=0;
else
v[x].push_back(-i);
q[i]=y;
}
int mex=0,lst=-1;
for (auto p=v.begin();p!=v.end();lst=p->first,++p){
for (int i=lst+1;i<p->first;/*++i*/){
while (c.find(mex)!=c.end())
mex++;
auto q=c.upper_bound(mex);
if (q==c.end()){
mex+=p->first-i;
break;
}
int tmp=min(*q-mex,p->first-i);
mex+=tmp;
i+=tmp;
}
int mn=INF;
for (int i=0;i<p->second.size();++i)
if (p->second[i]>=0)
mn=min(mn,p->second[i]);
while (c.find(mex)!=c.end())
mex++;
if (mex<mn)
c.insert(mex);
mn=min(mn,mex);
for (int i=0;i<p->second.size();++i)
if (p->second[i]>=0)
c.insert(p->second[i]);
else{
int y=q[-p->second[i]];
ans[-p->second[i]]=(y!=mn);
}
}
for (int i=1;i<=m;++i)
if (ans[i])
printf("WIN
");
else
printf("LOSE
");
return 0;
}