• 「BZOJ 1924」「SDOI 2010」所驼门王的宝藏「Tarjan」


    题意

    一个(r imes c)的棋盘,棋盘上有(n)个标记点,每个点有三种类型,类型(1)可以传送到本行任意标记点,类型(2)可以传送到本列任意标记点,类型(3)可以传送到周围八连通任意标记点。求最长路径。

    (r,cleq 10^6,nleq 10^5)

    题解

    这题做法很多,我就把每一行的所有类型(1)门缩到一起(直接找一个代表),列也同理,然后暴力连边,类型(3)连边用( ext{map}),这样每个点的入边中类型(1)(2)最多有(1)条,类型(3)最多(8)条,大概可以说明边数和点数同阶,于是( ext{Tarjan})缩点然后(dp)求最长路...

    #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
    ", ans);
        return 0;
    }
    
    
  • 相关阅读:
    HDU 逃离迷宫 (bfs)
    HDU 2588 GCD (欧拉函数)
    HDU 诡异的楼梯 (bfs)
    oj 二叉树相关
    AVL树代码实现
    用栈实现队列
    redis学习
    15. 三数之和 (思维)
    889. 根据前序和后序遍历构造二叉树(非递归)
    寻找重复的子树(dfs)
  • 原文地址:https://www.cnblogs.com/hongzy/p/10626369.html
Copyright © 2020-2023  润新知