---
# System prepended metadata

title: Codeforce 1237C2

---

---
title: Codeforce 1237C2
description: "Codeforce 1237C2 geometry"
---

<!-- toc -->

# Codeforce 1237C2 Balanced Removals (Harder) (幾何、思維)
今天我們來看看CF1237C2
[題目連結](https://codeforces.com/problemset/problem/1237/C2)

> **題目**
給你偶數個三維座標點，每次選其中兩點，如果兩點為對角的盒子(可以退化成2,1維)中不包含其他未移除的點，那麼就可以把這兩點移除。要輸出一個合法的移除順序

### 想法
如果現在只有一維，那麼問題就簡單了，把座標排序一下，兩個兩個移除就好。
所以我們如果能夠把問題化約到一維上就解決了。
觀察到，如果現在有n個(不保證偶數)一維的點，那麼刪除到最後會最多剩下一個點。利用這點，首先我們把同樣z座標的點分堆收集起來(圖形上來看:把在同樣x-y平面的點收集起來)，然後接著遞迴地處理:
對於每個x-y平面，把同樣y座標的點收集起來(圖形上來看:把在同樣x軸直線的點收集起來)...。
而每個降一個維度的點集處理完以後，有可能會有剩餘一個點無法處理，把這些點收集起來就會是一個一維的點集，就可以直接兩個兩個輸出了。

### 程式碼:
```c++
const int _n=5e4+10;
int t,n;
vector<VI> p(_n,VI(3));
int solve(VI& ids,int d){
  if(d==0)return ids[0];
  map<int,VI> mp;
  rep(i,0,SZ(ids))mp[p[ids[i]][d-1]].pb(ids[i]);
  VI left;
  for(auto& x:mp){
    int res=solve(x.se,d-1);
    if(res!=-1)left.pb(res);
  }
  for(int i=0;i+1<SZ(left);i+=2){cout<<left[i]+1<<' '<<left[i+1]+1<<'\n';}
  if(SZ(left)%2==1)return left.back();
  return -1;
}
main(void) {cin.tie(0);ios_base::sync_with_stdio(0);
  cin>>n;rep(i,0,n)rep(j,0,3)cin>>p[i][j];
  VI init;rep(i,0,n)init.pb(i);
  solve(init,3);
  return 0;
}
```
標頭、模板請點Submission看
[Submission](https://codeforces.com/contest/1237/submission/90325824)