洛谷 P2403 所駝門王的寶藏 —— tarjan + 最長路

題目鏈接:點我啊╭(╯^╰)╮

題目大意:

    rcr * c 的圖,有 nn 個寶藏點,寶藏點有有傳送門
    傳送門分三種:橫向任意飛、縱向任意飛、九宮格內任意飛
    初始點任意,求最多得到幾個寶藏???

解題思路:

    一眼望去縮點後 dpdp 。。。(也許真的是一眼吧)
    關鍵難點在於建圖,如果有 nn 個橫向的門,那麼邊數就成 n2n^2
    發現一個連通分量的點直接縮掉,也就是在同一行的橫向門當成環處理即可
    對於在同一行的非橫向門,建一條環指向這個點的邊即可
    所以排序處理一下即可,細節頗多,縱向門也同樣處理
    九宮格門直接暴力建即可
    跑完 tarjantarjan 之後求個最長路即可

#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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章