Luogu 2403 [SDOI2010]所驼门王的宝藏

BZOJ 1924

内存要算准,我MLE了两次。

建立$n + r + c$个点,对于一个点$i$的坐标为$(x, y)$,连边$(n + x, i)$和$(n + r + y, i)$,代表这一列和这一行可以走到它,如果类型为$1, 2$只要连一条到所在行和所在列的边就可以了,但是类型$3$似乎没有什么好的方法,$map$或者$hash$搞一搞,暴力连一连。

然后缩点之后记忆化搜索一下就可求出最长链了。

点数为$n + r + c$最多不超过$2e6 + 1e5$,边数为$2e5 + $最多$8e5$,不会达到这个上界。

时间复杂度$O(nlogn)$,$log$来源于$map$。

Code:

#include <cstdio>
#include <cstring>
#include <map>
#include <iostream>
#include <vector>
using namespace std;
typedef pair <int, int> pin;

const int N = 2e6 + 1e5 + 5;
const int M = 1e6 + 5;
const int dx[] = {-1, -1, -1, 0, 0, 1, 1, 1};
const int dy[] = {-1, 0, 1, -1, 1, -1, 0, 1};

int n, r, c, tot = 0, head[N], scc = 0, bel[N], f[N];
int dfsc = 0, dfn[N], low[N], top = 0, stk[N], deg[N];
bool vis[N];
map <pin, int> mp;
vector <int> G[N]; 

struct Edge {
    int to, nxt;
} e[M];

inline void add(int from, int to) {
    e[++tot].to = to;
    e[tot].nxt = head[from];
    head[from] = tot;
}

struct Node {
    int x, y, type;
} a[N];

inline void read(int &X) {
    X = 0; char ch = 0; int op = 1;
    for(; ch > '9' || ch < '0'; ch = getchar())
        if(ch == '-') op = -1;
    for(; ch >= '0' && ch <= '9'; ch = getchar())
        X = (X << 3) + (X << 1) + ch - 48;
    X *= op;
}

inline void chkMax(int &x, int y) {
    if(y > x) x = y;
}

inline int min(int x, int y) {
    return x > y ? y : x;
}

void tarjan(int x) {
    dfn[x] = low[x] = ++dfsc;
    vis[x] = 1, stk[++top] = x;
    for(int i = head[x]; i; i = e[i].nxt) {
        int y = e[i].to;
        if(!dfn[y]) {
            tarjan(y);
            low[x] = min(low[x], low[y]);
        } else if(vis[y])
            low[x] = min(low[x], dfn[y]);
    }
    
    if(low[x] == dfn[x]) {
        ++scc;
        for(; stk[top + 1] != x; --top) {
            vis[stk[top]] = 0;
            bel[stk[top]] = scc;
            if(stk[top] >= 1 && stk[top] <= n) ++f[scc];
        }
    }
}

void dfs(int x) {
    if(vis[x]) return;
    int res = 0, vecSiz = G[x].size();
    for(int i = 0; i < vecSiz; i++) {
        int y = G[x][i];
        dfs(y);
        chkMax(res, f[y]);
    }
    f[x] += res;
    vis[x] = 1;
}

int main() {
    read(n), read(r), read(c);
    for(int i = 1; i <= n; i++) {
        read(a[i].x), read(a[i].y), read(a[i].type);
        mp[pin(a[i].x, a[i].y)] = i;
        add(a[i].x + n, i), add(a[i].y + n + r, i);
    }
    for(int i = 1; i <= n; i++) {
        if(a[i].type == 1) add(i, a[i].x + n);
        if(a[i].type == 2) add(i, a[i].y + n + r);
        if(a[i].type == 3) {
            for(int j = 0; j < 8; j++) {
                int tox = a[i].x + dx[j], toy = a[i].y + dy[j];
                if(tox >= 1 && tox <= r && toy >= 1 && toy <= c) {
                    if(mp.find(pin(tox, toy)) != mp.end())
                        add(i, mp[pin(tox, toy)]);
                }
            }
        }
    }
    
    for(int i = 1; i <= n + r + c; i++)
        if(!dfn[i]) tarjan(i);
    
    for(int x = 1; x <= n + r + c; x++) {
        for(int i = head[x]; i; i = e[i].nxt) {
            int y = e[i].to;
            if(bel[x] == bel[y]) continue;
            G[bel[x]].push_back(bel[y]);
            ++deg[bel[y]];
        }
    }
    
    for(int i = 1; i <= scc; i++)
        if(!deg[i]) dfs(i);
    
    int ans = 0;
    for(int i = 1; i <= scc; i++)
        chkMax(ans, f[i]);
    
    printf("%d\n", ans);
    return 0;
}
View Code

 

posted @ 2018-10-25 08:24  CzxingcHen  阅读(181)  评论(0编辑  收藏  举报