首先是初始化节点的状态信息,记录每个节点的左节点编号以及右节点标号,然后删除那些没有遮挡别的节点并且没有被别的节点遮挡的节点,然后开始下面的循环删除节点的过程,因为被遮挡以及遮挡其他节点的总数是2*P,每次首先找出没有被删除的节点,并且记录当前节点的右节点以及右节点的下一个右节点,然后判断这两个节点是否是在同一个平面上,然后判断这两个节点对应的另外一个面上的节点是否满足对应的相邻关系,如果满足就将这四个节点全部删除,如果上面的情况不满足,就判断这两个节点是否满足遮挡关系,如果满足,那么就将这两个节点全部删除。然后继续迭代判断。最后判断是否这2*P个节点全部被删除了,如果全部被删除了,那么输出“YES”否则输出“NO”,具体实现见如下代码:
#include<iostream>
#include<vector>
#include<string>
#include<set>
#include<stack>
#include<queue>
#include<map>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<cstring>
#include<sstream>
#include<cstdio>
#include<deque>
#include<functional>
#include<utility>
using namespace std;
int L, P;
typedef struct Node{
int left, right, face;
}Node;
const int maxn = 1000000 + 10;
Node node[maxn];
int f[maxn],vis[maxn];
void del(int ind){
vis[ind] = 1;
node[node[ind].left].right = node[ind].right;
node[node[ind].right].left = node[ind].left;
}
int main(){
int T;
cin >> T;
for (int Case = 1; Case <= T; Case++){
cin >> L >> P;
for (int i = 0; i < L; i++){
node[i].left = i - 1;
node[i].right = i + 1;
vis[i] = false;
}
memset(f, 0, sizeof(f));
node[0].left = L - 1;
node[L - 1].right = 0;
for (int i = 0; i < P; i++){
int A, B;
cin >> A >> B;
f[A] = 1;
f[B] = -1;
node[B].face = A;
node[A].face = B;
}
for (int i = 0; i < L; i++){
if (f[i] == 0){
del(i);
}
}
int id = 0;
int amount = 2 * P;
int x, y;
while (amount){
bool out = true;
while (vis[id]) id++;
for (int i = node[id].right; out&&i != id;i=node[i].right){
x = i, y = node[i].right;
if (f[x] == f[y] && (node[node[x].face].right == node[y].face
|| node[node[y].face].right==node[x].face)){
del(x);
del(node[x].face);
del(y);
del(node[y].face);
amount -= 4;
out = false;
}
else if (node[x].face==y){
del(x);
del(y);
amount -= 2;
out = false;
}
}
if (out) break;
}
cout << "Case #" << Case << ": " << (amount ? "NO\n" : "YES\n");
}
return 0;
}