「BZOJ 1924」「SDOI 2010」所駝門王的寶藏「Tarjan」
阿新 • • 發佈:2019-03-30
cst include pac tex mat name scan c ++ main 縮點然後\(dp\)求最長路...
題意
一個\(r\times c\)的棋盤,棋盤上有\(n\)個標記點,每個點有三種類型,類型\(1\)可以傳送到本行任意標記點,類型\(2\)可以傳送到本列任意標記點,類型\(3\)可以傳送到周圍八連通任意標記點。求最長路徑。
\(r,c\leq 10^6,n\leq 10^5\)
題解
這題做法很多,我就把每一行的所有類型\(1\)門縮到一起(直接找一個代表),列也同理,然後暴力連邊,類型\(3\)連邊用\(\text{map}\),這樣每個點的入邊中類型\(1\)或\(2\)最多有\(1\)條,類型\(3\)最多\(8\)條,大概可以說明邊數和點數同階,於是\(\text{Tarjan}\)
#include <algorithm> #include <utility> #include <cstdio> #include <vector> #include <stack> #include <map> using namespace std; const int N = 1e5 + 10; const int dx[] = {1, 0, -1, 0, 1, 1, -1, -1}; const int dy[] = {0, 1, 0, -1, -1, 1, -1, 1}; struct node { int x, y, z, sz; } a[N]; int n, r, c, f[N], rt[2][N * 10], dT[N]; vector<int> ob[2][N * 10], G[N], T[N]; map<pair<int, int>, int> ma; bool isr[N]; int dfn[N], low[N], sz[N], bel[N], scc; stack<int> st; bool ins[N]; void tarjan(int u) { low[u] = dfn[u] = ++ dfn[0]; st.push(u); ins[u] = 1; for(int i = 0; i < G[u].size(); i ++) { int v = G[u][i]; if(!dfn[v]) { tarjan(v); low[u] = min(low[u], low[v]); } else if(ins[v]) { low[u] = min(low[u], dfn[v]); } } if(low[u] == dfn[u]) { scc ++; while(1) { int v = st.top(); st.pop(); ins[v] = 0; bel[v] = scc; sz[scc] += a[v].sz; if(u == v) break ; } } } int pa[N]; int solve(int u) { if(pa[u]) return pa[u]; for(int i = 0; i < T[u].size(); i ++) { pa[u] = max(pa[u], solve(T[u][i])); } pa[u] += sz[u]; return pa[u]; } int main() { scanf("%d%d%d", &n, &r, &c); for(int i = 1; i <= n; i ++) { scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].z); ma[make_pair(a[i].x, a[i].y)] = i; ob[0][a[i].x].push_back(i); ob[1][a[i].y].push_back(i); a[i].sz = 0; } for(int i = 1; i <= n; i ++) { if(a[i].z == 1) { int &u = rt[0][a[i].x]; if(!u) u = i; a[u].sz ++; f[i] = u; } if(a[i].z == 2) { int &u = rt[1][a[i].y]; if(!u) u = i; a[u].sz ++; f[i] = u; } if(a[i].z == 3) { f[i] = i; a[i].sz ++; } isr[f[i]] = 1; } for(int i = 1; i <= n; i ++) if(isr[i]) { if(a[i].z == 1) { for(int j = 0; j < ob[0][a[i].x].size(); j ++) { int v = ob[0][a[i].x][j]; G[i].push_back(f[v]); } } if(a[i].z == 2) { for(int j = 0; j < ob[1][a[i].y].size(); j ++) { int v = ob[1][a[i].y][j]; G[i].push_back(f[v]); } } if(a[i].z == 3) { for(int j = 0; j < 8; j ++) { int v = ma[make_pair(a[i].x + dx[j], a[i].y + dy[j])]; if(v) { G[i].push_back(f[v]); } } } } for(int i = 1; i <= n; i ++) if(isr[i] && !dfn[i]) { tarjan(i); } for(int i = 1; i <= n; i ++) { if(isr[i]) { for(int j = 0; j < G[i].size(); j ++) { int v = G[i][j]; if(bel[i] != bel[v]) { T[bel[i]].push_back(bel[v]); dT[bel[v]] ++; } } } } int ans = 0; for(int i = 1; i <= scc; i ++) if(!dT[i]) { ans = max(ans, solve(i)); } printf("%d\n", ans); return 0; }
「BZOJ 1924」「SDOI 2010」所駝門王的寶藏「Tarjan」