[BZOJ1924][Sdoi2010]所驼门王的宝藏
Description
Input
第一行给出三个正整数 N, R, C。 以下 N 行,每行给出一扇传送门的信息,包含三个正整数xi, yi, Ti,表示该传送门设在位于第 xi行第yi列的藏宝宫室,类型为 Ti。Ti是一个1~3间的整数, 1表示可以传送到第 xi行任意一列的“横天门”,2表示可以传送到任意一行第 yi列的“纵寰门”,3表示可以传送到周围 8格宫室的“自由men”。 保证 1≤xi≤R,1≤yi≤C,所有的传送门位置互不相同。
Output
只有一个正整数,表示你确定的路线所经过不同藏宝宫室的最大数目。
Sample Input
10 7 7
2 2 1
2 4 2
1 7 2
2 7 3
4 2 2
4 4 1
6 7 3
7 7 1
7 5 2
5 2 1
2 2 1
2 4 2
1 7 2
2 7 3
4 2 2
4 4 1
6 7 3
7 7 1
7 5 2
5 2 1
Sample Output
9
这题吼啊,也就是调了我2个小时。
显然的思路:建图然后Tarjan缩点,再跑拓扑找最长链。
但是暴力连边显然会T,如果1e5的点全是“横天门”,全在一行上,然后连边复杂度成功到$O(N^2)$。
但是我们发现,一行上的横天门,和一列上的纵寰门其实在跑完Tarjan之后都是一个点,也就是他们都是可以相互到达的,所以我们根本不用连那么多边,只需要把一行上的横天门,或者一列上的纵寰门连成一个环就行了。
所以这题的建图过程就是:
1.把一行上的横天门,和一列上的纵寰门都连成一个环。
2.把一行上的不是横天门的点连上随意一个这一行上的横天门,列上类似。
3.暴力把自由men连边(问问问,为什么自由men是违规内容啊)。
我是用vecotr存储每行每列上的点的,但是vector内存消耗巨大...
用vector暴力写在luogu上MLE三个点,在bzoj上A了...玄学。
于是开始了漫长的卡空间...过程省略...
其实调了半天,最后就把坐标离散化了一下,然后每个vector都少了10倍内存,然后就在luogu上过了...
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <vector> #include <map> using namespace std; #define reg register inline int read() { int res = 0;char ch=getchar();bool fu=0; while(!isdigit(ch))fu|=(ch=='-'),ch=getchar(); while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48),ch=getchar(); return fu?-res:res; } #define N 100005 #define M 1000005 int n, R, C; struct Trea { int x, y, typ; }te[N]; struct edge { int nxt, to; }ed[N*2]; int head[N], cnt; inline void add(int x, int y) { ed[++cnt] = (edge){head[x], y}; head[x] = cnt; } #define pii pair<int, int> #define mkp make_pair int mp1[M], mp2[M]; int mm1, mm2; vector <int> v1[N], v2[N], v3[N], v4[N]; map <pii, int> mp; int dfn[N], low[N], timc, stack[N], top, belong[N], siz[N], numc; bool ins[N]; void Tarjan(int x) { dfn[x] = low[x] = ++timc; stack[++top] = x, ins[x] = 1; for (reg int i = head[x] ; i ; i = ed[i].nxt) { int to = ed[i].to; if (!dfn[to]) Tarjan(to), low[x] = min(low[x], low[to]); else if (ins[to]) low[x] = min(low[x], dfn[to]); } if (dfn[x] == low[x]) { numc++; int y = 0; do { y = stack[top--]; ins[y] = 0; belong[y] = numc; siz[numc]++; } while(y != x); } } vector <int> edg[N]; int deg[N]; int f[N], ans; int main() { n = read(), R = read(), C = read(); for (reg int i = 1 ; i <= n ; i ++) { te[i] = (Trea){read(), read(), read()}; if (!mp1[te[i].x]) mp1[te[i].x] = ++mm1; if (!mp2[te[i].y]) mp2[te[i].y] = ++mm2; if (te[i].typ == 1) v1[mp1[te[i].x]].push_back(i); else if (te[i].typ == 2) v2[mp2[te[i].y]].push_back(i); mp[mkp(te[i].x, te[i].y)] = i; v3[mp1[te[i].x]].push_back(i), v4[mp2[te[i].y]].push_back(i); } for (reg int i = 1 ; i <= R ; i ++) { if (!mp1[i]) continue; if (v1[mp1[i]].size() == 0) continue; for (reg int j = 1 ; j < (signed)v1[mp1[i]].size() ; j ++) add(v1[mp1[i]][j], v1[mp1[i]][j - 1]); if (v1[mp1[i]].size() >= 2) add(v1[mp1[i]][0], v1[mp1[i]][v1[mp1[i]].size()-1]); for (reg int j = 0 ; j < (signed)v3[mp1[i]].size() ; j ++) if (te[v3[mp1[i]][j]].typ != 1) add(v1[mp1[i]][0], v3[mp1[i]][j]); } for (reg int i = 1 ; i <= C ; i ++) { if (!mp2[i]) continue; if (v2[mp2[i]].size() == 0) continue; for (reg int j = 1 ; j < (signed)v2[mp2[i]].size() ; j ++) add(v2[mp2[i]][j], v2[mp2[i]][j - 1]); if (v2[mp2[i]].size() >= 2) add(v2[mp2[i]][0], v2[mp2[i]][v2[mp2[i]].size()-1]); for (reg int j = 0 ; j < (signed)v4[mp2[i]].size() ; j ++) if (te[v4[mp2[i]][j]].typ != 2) add(v2[mp2[i]][0], v4[mp2[i]][j]); } for (reg int i = 1 ; i <= n ; i ++) { if (te[i].typ != 3) continue; for (reg int p = max(1, te[i].x - 1) ; p <= min(R, te[i].x + 1) ; p ++) for (reg int q = max(1, te[i].y - 1) ; q <= min(C, te[i].y + 1) ; q ++) if (p != te[i].x or q != te[i].y) if (mp[mkp(p, q)]) add(i, mp[mkp(p, q)]); } for (reg int i = 1; i <= n ; i ++) if (!dfn[i]) Tarjan(i); for (reg int x = 1 ; x <= n ; x ++) for (reg int i = head[x] ; i ; i = ed[i].nxt) { int y = ed[i].to; if (belong[x] == belong[y]) continue; edg[belong[y]].push_back(belong[x]); deg[belong[x]]++; } queue <int> q; for (reg int i = 1 ; i <= numc ; i ++) {f[i]=siz[i];if(!deg[i])q.push(i);} while(!q.empty()) { int x = q.front();q.pop(); for (reg int i = 0 ; i < (signed)edg[x].size() ; i ++) { int to = edg[x][i]; --deg[to]; f[to] = max(f[to], f[x] + siz[to]); if (!deg[to]) q.push(to); } } for (reg int i = 1 ; i <= numc ; i ++) ans = max(ans, f[i]); cout << ans << endl; return 0; }