2 1 0 0 1 6 -100 0 90 -50 0 1 -20 0 1 100 0 90 47 0 1 23 0 1
Alice Bob
显然圆的包含关系可以构成一片森林,然后问题就可以转化为:每一步可以删除森林的一棵树或者某树的一棵子树,不能删者输。这样,问题就变成经典的树上删边游戏了。
树上删边游戏有一个很重要的结论:叶子节点的SG值为0,中间节点的SG值为它的所有子节点的SG值加1后的异或和。(证明详见贾志豪论文《组合游戏略述——浅谈SG游戏的若干拓展及变形》)
现在,我们的主要问题就是如何把圆的包含关系转化为森林。这里要用到圆的扫描线算法。首先对于每个圆,创建两个时间点,一个进入一个离开,再对所有时间点从小到大排序。然后逐个处理时间点,用set维护所有圆,每遇到一个进入时间,分情况讨论圆的位置关系,然后把这个圆插入set中。每遇到一个离开时间,从set中删除这个圆。
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<cstdlib> #include<algorithm> #include<set> #define F(i,j,n) for(int i=j;i<=n;i++) #define D(i,j,n) for(int i=j;i>=n;i--) #define ll long long #define maxn 20010 using namespace std; int t,n,cnt,tt,tmp; int head[maxn],fa[maxn]; struct cir{int x,y,r;}a[maxn]; struct edge_type{int next,to;}e[maxn*2]; struct bor { int x,f,id; friend bool operator < (bor a,bor b) { if (a.x==b.x) return a.f<b.f; return a.x<b.x; } }q[maxn*2]; double get_h(int id,int x,int opt) { return a[id].y+opt*sqrt(a[id].r*a[id].r-(a[id].x-x)*(a[id].x-x)); } struct pos { int id,opt; pos(int a=0,int b=0){id=a;opt=b;} friend bool operator < (pos a,pos b) { if (a.id==b.id) return a.opt<b.opt; return get_h(a.id,tmp,a.opt)<get_h(b.id,tmp,b.opt); } }; set<pos> s; set<pos>::iterator it; inline int read() { int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline void add_edge(int x,int y) { e[++cnt]=(edge_type){head[x],y}; head[x]=cnt; fa[y]=x; } inline ll get(int x) { ll ret=0; for(int i=head[x];i;i=e[i].next) ret^=get(e[i].to); return ret+1; } int main() { t=read(); while (t--) { cnt=tt=0; memset(fa,0,sizeof(fa)); memset(head,0,sizeof(head)); n=read(); F(i,1,n) { a[i].x=read();a[i].y=read();a[i].r=read(); q[++tt]=(bor){a[i].x-a[i].r,1,i}; q[++tt]=(bor){a[i].x+a[i].r,-1,i}; } sort(q+1,q+tt+1); F(i,1,tt) { if (q[i].f==1) { tmp=q[i].x; it=s.lower_bound(pos(q[i].id,1)); if (it!=s.end()) { if (it->opt==1) add_edge(it->id,q[i].id); else if (fa[it->id]) add_edge(fa[it->id],q[i].id); } s.insert(pos(q[i].id,1)); s.insert(pos(q[i].id,-1)); } else { s.erase(pos(q[i].id,1)); s.erase(pos(q[i].id,-1)); } } ll sum=0; F(i,1,n) if (!fa[i]) sum=sum^get(i); puts(sum?"Alice":"Bob"); } }