P2403 [SDOI2010]所驼门王的宝藏

啊这

优化建图题调的时候一定要把整个图画出来然后自己慢慢看

还有就是图论中基础板子一定不能写错了

对于此题,我们建n+R+C个点

R:表示行电梯,乘上该电梯可以到达所有同一行的点

C:表示列电梯....

然后对于一个点i,如果是一二类边,我们就把另一类的电梯向他连边,并从该点向对应特征电梯连边!

最后还有第三类边,可以直接暴力,用一个map存一下每个点的pair即可!

时间复杂度O(nlogn),复杂度在于map


#include<bits/stdc++.h>
#define mkp(x,y) (make_pair(x,y))
const int MAXN = 5e5 + 7;
const int MAXM = 2e6 + 7;
using namespace std;
map<pair<int, int>, int> mp;
int n, R, C, T;
const int dx[] = {-1, -1, -1, 0, 0, 1, 1, 1};
const int dy[] = {-1, 0, 1, -1, 1, -1, 0, 1};
int H[MAXM], L[MAXM], in[MAXN], d[MAXN], first[MAXN];
int hd, que[MAXN], tl, dis[MAXN], fl[MAXN];
int ccnt2, exn;
int a[MAXN], S[MAXN];

struct rec {
	int nxt, to;
} e[MAXM];
struct NODE {
	int x, y, t;
} nd[MAXN];


inline void tpdp() {
	puts("In tpdp");
	for(int i = 1; i <= exn; ++i) {
		if(in[i] == 0) {
			que[tl++] = i;
			dis[i] = S[i];
			// printf("起点 :%d %d? %d\n",  i, S[i], in[i]);
		}
	}

	while(hd <= tl) {
		int u = que[hd];
		++hd;
		// printf("poor boy:%d?\n", u);
		for(int i = first[u]; i; i = e[i].nxt) {
			int v = e[i].to;
			in[v]--;
			// printf("update%d %d %d->\n", dis[u], dis[v], S[v]);
			dis[v] = max(dis[u] + S[v], dis[v]);
			if(!in[v]) {
				que[++tl] = v;
			}
		}
	}

	return ;
}
int ccnt, home[MAXN], nxt[MAXM], to[MAXM];
inline void ct(int x, int y) {
	ccnt++;
	nxt[ccnt] = home[x];
	home[x] = ccnt;
	to[ccnt] = y;
}

inline void ct2(int x, int y) {
	ccnt2++;
	e[ccnt2].nxt = first[x];
	first[x] = ccnt2;
	e[ccnt2].to = y;
	in[y]++;
}

int dfn[MAXN], low[MAXN], depp, st[MAXN], tp;
inline void tarjan(int u) {
	dfn[u] = ++depp;
	low[u] = dfn[u];
	st[++tp] = u;
	fl[u] = 1;
	// printf("now we in node:%d %d?\n", u, dfn[u]);
	for(int i = home[u]; i; i = nxt[i]) {
		int v = to[i];
		if(!dfn[v]) {
			tarjan(v);
			low[u] = min(low[u], low[v]);
		} else if(!fl[v])continue;
		low[u] = min(low[u], dfn[v]);
	}
	// printf("so the %d' low is %d?\n", u, low[u]);
	if(low[u] == dfn[u]) {
		exn++;
		while(st[tp] != u) {
			int v = st[tp];
			--tp;
			S[exn] += a[v];
			d[v] = exn;
			fl[v] = 0;
		}
		tp--;
		S[exn] += a[u];
		d[u] = exn;
		fl[u] = 0;
		// printf("%d?%d\n", tp, exn);
	}
	return ;
}

int main() {
	scanf("%d%d%d", &n, &R, &C);
	T = n;
	for(int i = 1; i <= n; ++i) {
		scanf("%d%d%d", &nd[i].x, &nd[i].y, &nd[i].t);
		if(!L[nd[i].y])L[nd[i].y] = ++T;
		if(!H[nd[i].x])H[nd[i].x] = ++T;
		// printf("%d %d\n", L[nd[i].y], H[nd[i].x]);
		if(nd[i].t == 1) {
			ct(H[nd[i].x], i);
			ct(i, H[nd[i].x]);
			ct(L[nd[i].y], i);//列只能被动接受
		}
		if(nd[i].t == 2) {
			ct(H[nd[i].x], i);//行只能被动接受
			ct(L[nd[i].y], i);
			ct(i, L[nd[i].y]);
		}
		if(nd[i].t == 3) {
			ct(H[nd[i].x], i);
			ct(L[nd[i].y], i);//都只能被迫接受
		}
		a[i] = 1;
		mp[mkp(nd[i].x, nd[i].y)] = i;
	}
	for(int i = 1; i <= n; ++i) {
		if(nd[i].t == 3) {
			for(int k = 0; k < 8; ++k) {
				int nx = dx[k] + nd[i].x;
				int ny = dy[k] + nd[i].y;
				// printf("%d %d?\n", nx, ny);
				if(mp.find(mkp(nx, ny)) != mp.end()) {
					// printf("U:%d?%d\n", nx, ny);
					ct(i, mp[mkp(nx, ny)]);
				}
			}
		}
	}
	for(int i = 1; i <= T; ++i) {
		if(!dfn[i])
			tarjan(i);
	}
	for(int u = 1; u <= T; ++u) {
		// printf("where is Kindom!:%d here %d have lots of %d\n", u, d[u], S[d[u]]);
		for(int i = home[u]; i; i = nxt[i]) {
			int v = to[i];
			if(d[u] == d[v])continue;
			// printf("I'm %d and belong to %d:edge to %d?\n", u, d[u], d[v]);
			ct2(d[u], d[v]);
		}
	}
	tpdp();
	int ans = 0;
	for(int i = 1; i <= exn; ++i) {
		// printf("%d %d\n", i, dis[i]);
		ans = max(ans, dis[i]);
	}
	printf("%d\n", ans);
	return 0;
}