题目链接:点我啊╭(╯^╰)╮
题目大意:
r
∗
c
r * c
r∗c 的图,有
n
n
n 个宝藏点,宝藏点有传送门
传送门分三种:横向任意飞、纵向任意飞、九宫格内任意飞
初始点任意,求最多得到几个宝藏???
解题思路:
一眼望去缩点后
d
p
dp
dp 。。。(也许真的是一眼吧)
关键难点在于建图,如果有
n
n
n 个横向的门,那么边数就成
n
2
n^2
n2 了
发现一个连通分量的点直接缩掉,也就是在同一行的横向门当成环处理即可
对于在同一行的非横向门,建一条环指向这个点的边即可
所以排序处理一下即可,细节颇多,纵向门也同样处理
九宫格门直接暴力建即可
跑完
t
a
r
j
a
n
tarjan
tarjan 之后求个最长路即可
#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
const int maxn = 1e5 + 5;
int dx[10] = {1, 1, 1, 0, 0, -1, -1, -1};
int dy[10] = {1, 0, -1, 1, -1, 1, 0, -1};
map <pii, int> mp;
vector <int> g[maxn], g2[maxn];
struct node{
int x, y, op, id;
} p[maxn];
int n, r, c, ans, tot, top, numc;
int dfn[maxn], low[maxn], vis[maxn], st[maxn];
int dp[maxn], sum[maxn], col[maxn];
inline void add(int u, int v){
g[u].push_back(v);
}
bool xcmp(const node &A, const node &B){
if(A.x ^ B.x) return A.x < B.x;
if(A.op == 1) return true;
if(B.op == 1) return false;
return A.y < B.y;
}
bool ycmp(const node &A, const node &B){
if(A.y ^ B.y) return A.y < B.y;
if(A.op == 2) return true;
if(B.op == 2) return false;
return A.x < B.x;
}
void tarjan(int u){
dfn[u] = low[u] = ++tot;
st[++top] = u;
vis[u] = 1;
for(auto v : g[u]){
if(!dfn[v]){
tarjan(v);
low[u] = min(low[u], low[v]);
} else if(vis[v]) low[u] = min(low[u], dfn[v]);
}
if(dfn[u] == low[u]){
++numc;
while(st[top+1] ^ u){
col[st[top]] = numc;
sum[numc]++;
vis[st[top--]] = 0;
}
}
}
void dfs(int u, int fa){
if(dp[u] > sum[u]) return;
dp[u] = sum[u];
for(auto v : g2[u]){
if(v == fa) continue;
dfs(v, u);
dp[u] = max(dp[u], dp[v] + sum[u]);
}
}
signed main() {
scanf("%d%d%d", &n, &r, &c);
for(int i=1; i<=n; i++){
scanf("%d%d%d", &p[i].x, &p[i].y, &p[i].op);
p[i].id = mp[{p[i].x, p[i].y}] = i;
}
sort(p+1, p+1+n, xcmp);
for(int i=1, fi=1, la=1; i<=n; i++){
if(p[i].x ^ p[i+1].x){
if(fi ^ la) add(p[la].id, p[fi].id);
fi = la = i + 1;
} else{
if(p[la].op == 1) add(p[la].id, p[i+1].id);
if(p[i+1].op == 1) la = i + 1;
if(p[fi].op ^ 1) fi = la = i + 1;
}
}
sort(p+1, p+1+n, ycmp);
for(int i=1, fi=1, la=1; i<=n; i++){
if(p[i].y ^ p[i+1].y){
if(fi ^ la) add(p[la].id, p[fi].id);
fi = la = i + 1;
} else{
if(p[la].op == 2) add(p[la].id, p[i+1].id);
if(p[i+1].op == 2) la = i + 1;
if(p[fi].op ^ 2) fi = la = i + 1;
}
}
for(int i=1; i<=n; i++){
if(p[i].op ^ 3) continue;
for(int j=0; j<8; j++)
if(mp.count({p[i].x+dx[j], p[i].y+dy[j]}))
add(p[i].id, mp[{p[i].x+dx[j], p[i].y+dy[j]}]);
}
for(int i=1; i<=n; i++)
if(!dfn[i]) tarjan(i);
for(int i=1; i<=n; i++) {
for(auto v : g[i])
if(col[i] ^ col[v])
g2[col[i]].push_back(col[v]);
}
for(int i=1; i<=numc; i++){
if(dp[i] <= sum[i]) dfs(i, 0);
ans = max(ans, dp[i]);
}
printf("%d\n", ans);
}