[无聊测试赛] T10 所驼门王的宝藏
码农题.思维难度中等,难在调试
建边方法:分别将x和y排序,对每个点,对它旁边所有的x/y连边(如果他需要). 开map记录点的位置,对于每个点,如果他的九宫格之内有其他点,就对他连边
注意排序会使点的顺序混乱,故需要在状态里将点的id保存
连完边跑tarjan缩点.易证如果你能到一个环内的某个点,你就可以到达这个环内的每个点.每个环的权值为他里面的点数量.将各个环转化为一个新图
可以发现新图已经转化为一个DAG.可以选择用dfs/topo来记录答案.这里我选择用dfs.
dfs每个未经过的点并统计经过这个点能得到的宝藏数量,取最大值
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#include <unordered_map>
#include <cstring>
#include <stack>
using namespace std;
const int MAXN = 1e5+5;
int n,r,c,dp[MAXN],curr,ans;
int pre,dfn[MAXN],low[MAXN],head[MAXN],num[MAXN],in[MAXN];
unordered_map<int, unordered_map<int,int> > mp, inq;
vector<int> adj[MAXN],adj2[MAXN],tmp[MAXN];
stack<int> st;
int x_[8] = {1,0,-1,0,1,1,-1,-1};
int y_[8] = {0,1,0,-1,1,-1,1,-1};//九宫格
bool vis[MAXN];
struct Edge{
int x,y,type,id;
}edge[MAXN],edge2[MAXN];
inline bool sorted1(Edge a, Edge b){
return a.x<b.x || (a.x==b.x && a.type==1);
}//x排序
inline bool sorted2(Edge a, Edge b){
return a.y<b.y || (a.y==b.y && a.type==2);
}//y排序
inline void add_x(){
sort(edge+1,edge+n+1,sorted1);
int prev = 0;
for (int i=1;i<=n;i++){
if (edge[i].type!=1) continue;//如果他自己不能连
int f = edge[i].id;
int nxt = i-1;
while(nxt>0){
if (edge[nxt].x!=edge[i].x) break;
int t = edge[nxt].id;
adj[f].push_back(t);
nxt--;
}//往左连
nxt = i+1;
while(nxt<=n){
int t = edge[nxt].id;
if (edge[nxt].x!=edge[i].x) break;
adj[f].push_back(t);
nxt++;
}//往右连
}
}
inline void add_y(){
sort(edge+1,edge+n+1,sorted2);
int prev = 0;
for (int i=1;i<=n;i++){
if (edge[i].type!=2) continue;
int f = edge[i].id;
int nxt = i-1;
while(nxt>0){//往左
int t = edge[nxt].id;
if (edge[nxt].y!=edge[i].y) break;
adj[f].push_back(t);
nxt--;
}
nxt = i+1;
while(nxt<=n){//往右
int t = edge[nxt].id;
if (edge[nxt].y!=edge[i].y) break;
adj[f].push_back(t);
nxt++;
}
}
}
inline void add_xy(){//九宫格连
for (int i=1;i<=n;i++){
if (edge[i].type!=3) continue;
int f = edge[i].id;
for (int j=0;j<8;j++){
int to_x = edge[i].x+x_[j], to_y = edge[i].y+y_[j];
if (mp[to_x][to_y] ){
int t = mp[to_x][to_y];
if (!inq[f][t]){inq[f][t] = true;adj[f].push_back(t);}
}
}
}
}
void tarjan(int pos){//裸的tarjan
st.push(pos);
vis[pos] = true;
dfn[pos] = low[pos] = ++pre;
for (int v : adj[pos]){
if (!dfn[v]){
tarjan(v);
low[pos] = min(low[pos],low[v]);
}else if (vis[v]) low[pos] = min(low[pos],dfn[v]);
}
if (dfn[pos]==low[pos]) {
curr++;
while(st.size()){
int stt = st.top();
head[stt] = curr;
tmp[curr].push_back(stt);
num[curr]++;
st.pop();
vis[stt] = false;
if (stt==pos) break;
}
}
}
void dfs(int pos){//dfs找子叶权值
dp[pos] = num[pos];
int addi = 0;
for (int v : adj2[pos]){
if (!dp[v]) dfs(v);
addi = max(addi,dp[v]);
}
dp[pos]+=addi;
}
int main(){
cin >> n >> r >> c;
for (int i=1;i<=n;i++) {
cin >> edge[i].x >> edge[i].y >> edge[i].type;edge[i].id = i;
edge2[i] = edge[i];
mp[edge[i].x][edge[i].y] = i;
}
add_x();
add_y();
add_xy();
for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i);
for (int i=1;i<=curr;i++){//建新图
memset(vis,0,sizeof(vis));
vis[i] = true;
for (int u : tmp[i]){
for (int v : adj[u]){
if (!vis[head[v]]){
vis[head[v]] = true;
adj2[i].push_back(head[v]);
}
}
}
}
memset(vis,0,sizeof(vis));
for (int i=1;i<=curr;i++){//找答案
if (!vis[i]){
dfs(i);
ans = max(ans,dp[i]);
}
}
cout << ans;
}