【題解】CF1458E Nim Shortcuts
阿新 • • 發佈:2021-06-25
比 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\)
這等價於刪去一行或一列。如果 \(x<y\) 則刪除第 \(y\) 列,如果 \(x>y\) 則刪除第 \(x\) 行,如果 \(x=y\) ,這本來就是必敗態,不需要改變。
所以我們只用支援刪除行/列,和原來網格中的 \((a,b)\) 在刪除了這些行/列後的新位置 \((a,b)\) 。
這等價於查詢 \(\le a/b\) 的行/列中被刪除了多少個,經典二維數點問題,離線後用樹狀陣列維護。時間複雜度 \(\mathcal{O}(N\log N)\)。
需要注意一些細節。需要特判 \((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; }