题解:
Basically, the first player should maximize the lexicographical order of numbers, and the second player should minimize it. Thus, at every move the first player should choose the largest available number, and the second should choose the minimal one.
First of all, how do we check if the cube can be removed? It is impossible only if there is some cube "supported" by it (i.e., it has coordinates (x - 1, y + 1), (x, y + 1), (x + 1, y + 1)) such that our cube is the only one supporting it. This can be checked explicitly. The large coordinates' limitations do not allow us to store a simply array for that, so we should use an associative array, like a set
in C++.
Now we should find the maximal/minimal number that can be removed. A simple linear search won't work fast enough, so we store another data structure containing all numbers available to remove; the structure should allow inserting, erasing and finding global minimum/maximum, so the set
C++ structure fits again.
When we've made our move, some cubes may have become available or unavailable to remove. However, there is an O(1) amount of cubes we have to recheck and possibly insert/erase from our structure: the cubes (x ± 1, y) and (x ± 2, y) may have become unavailable because some higher cube has become dangerous (that is, there is a single cube supporting it), and some of the cubes(x - 1, y - 1), (x, y - 1) and (x + 1, y - 1) may have become available because our cube was the only dangerous cube that it has been supporting. Anyway, a simple recheck for these cubes will handle all the cases.
This solution is if using the appropriate data structure.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<utility>
#include<queue>
#include<set>
#include<map>
#include<math.h>
#include<string>
using namespace std;
#define inf 0x3f3f3f3f
#pragma warning(disable:4996)
#pragma comment(linker, "/STACK:102400000,102400000")
#define ll long long
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define mem(a,b) memset(a,b,sizeof(a))
const double eps = 1e-9;
const ll mod = 1e9 + 9;
map<pair<int, int>, int> m;
struct node
{
int x, y, id;
bool operator<(const node &I) const{
return id < I.id;
}
}p[200020];
set<node> s;
int f[200010]; //标记已经使用的,就是set中已经删除的
int vis[200020]; //标记当前可以移动的,在set里里面的
bool ok(node s, node t)//存在非t块 的其他块支撑
{
for (int i = -1; i <= 1; i++)
{
node r;
r.y = s.y - 1;
r.x = s.x + i;
if (m[mp(r.x, r.y)] != 0 && r.x != t.x && f[m[mp(r.x, r.y)]-1] == 0)
return true;
}
return false;
}
bool is_ok_rm(node t)
{
for (int i = -1; i <= 1; i++)
{
node r;
r.y = t.y + 1;
r.x = t.x + i;
if (m[mp(r.x, r.y)] == 0) continue;
if (f[m[mp(r.x, r.y)]-1] == 1) continue;
if (!ok(r, t))
return false;
}
return true;
}
void del(node t)
{
for (int i = -1; i <= 1; i++)
{
node r;
r.y = t.y - 1;
r.x = t.x + i;
if (m[mp(r.x, r.y)] == 0) continue;
if (f[m[mp(r.x, r.y)] - 1] == 1) continue;
if (is_ok_rm(r))
{
r.id = m[mp(r.x, r.y)]-1;
s.insert(r);
vis[r.id] = 1;
}
}
for (int i = -2; i <= 2; i++)
{
if (i == 0) continue;
node r;
r.y = t.y;
r.x = t.x + i;
int h = m[mp(r.x, r.y)];
if (h != 0 && vis[h - 1] == 1 && !is_ok_rm(r))
{
r.id = h - 1;
vis[h - 1] = 0;
s.erase(r);
}
}
}
int main()
{
int n;
cin >> n;
memset(f, 0, sizeof(f));
mem(vis,0);
for (int i = 1; i <= n; i++)
{
scanf("%d%d", &p[i].x, &p[i].y);
p[i].id = i - 1;
m[mp(p[i].x,p[i].y)] = i;
}
for (int i = 1; i <= n; i++)
{
if (is_ok_rm(p[i]))
{
s.insert(p[i]);
vis[p[i].id] = 1;
}
}
ll ans = 0;
for (int i = 1; i <= n; i++)
{
node t;
if (i % 2 == 1)
t = *(s.rbegin());
else
t = *(s.begin());
ans = ans*n%mod + t.id;
s.erase(t);
f[t.id] = 1;
del(t);
}
cout << ans << endl;
//system("pause");
}