bzoj 1924

所用点的编号为输入顺序,因为只有在存在联通门的宫室中存在宝藏。其余点不考虑
对于每一行,选定一个横天门,向该行横天门连双向边,其余门单向边
纵列同理
自.由门用map判周围八个点是否存在,存在即连边
Tarjan缩点后DAG上dp求最长路

bzoj 可过,luogu卡空间

#include <bits/stdc++.h>

#define gc getchar()

inline int read() {
    int x = 0;
    char c = gc;
    while(c < '0' || c > '9') c = gc;
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
    return x;
}

const int N = 1e5 + 4, M = 1e6 + 4;
const int xd[] = {0, -1, -1, -1, 0, 1, 1, 1};
const int yd[] = {-1, -1, 0, 1, 1, 1, 0, -1};

int head[N], head_2[N], cnt;
struct Node {
    int u, v, nxt;
};
Node G[M], E[M];

std:: vector <int> Vecx[M], Vecy[M];
std:: map <int, int> Map[M];
int X[N], Y[N], Opt[N];
int Q, n, m;
int Low[N], Dfn[N], Stack[N], Belong[N], Size[N], Scc, Tim, topp;
bool vis[N];

inline void Add_1(int u, int v) {
    if(u == v) return ;
    G[++ cnt].v = v;
    G[cnt].nxt = head[u];
    head[u] = cnt;
}
inline void Add_2(int u, int v) {
    E[++ cnt].v = v;
    E[cnt].nxt = head_2[u];
    head_2[u] = cnt;
}

inline void Build() {
    memset(head, -1, sizeof head);
    for(int i = 1; i <= n; i ++) {
        int x = 0, s = Vecx[i].size();
        for(int j = 0; j < s; j ++) {
            if(Opt[Vecx[i][j]] == 1) {
                x = Vecx[i][j]; break;
            }
        }
        for(int j = 0; j < s; j ++) {
            Add_1(x, Vecx[i][j]);
            if(Opt[Vecx[i][j]] == 1) Add_1(Vecx[i][j], x);
        }
    }
    for(int i = 1; i <= m; i ++) {
        int y = 0, s = Vecy[i].size();
        for(int j = 0; j < s; j ++) {
            if(Opt[Vecy[i][j]] == 2) {
                y = Vecy[i][j]; break;
            }
        }
        for(int j = 0; j < s; j ++) {
            Add_1(y, Vecy[i][j]);
            if(Opt[Vecy[i][j]] == 2) Add_1(Vecy[i][j], y);
        }
    }
    for(int i = 1; i <= Q; i ++) {
        if(Opt[i] == 3) {
            for(int j = 0; j < 8; j ++) {
                int t = Map[X[i] + xd[j]][Y[i] + yd[j]];
                if(t) Add_1(i, t);
            }

        }
    }
}

void Tarjan(int x) {
    Low[x] = Dfn[x] = ++ Tim;
    Stack[++ topp] = x;
    vis[x] = 1;
    for(int i = head[x]; ~ i; i = G[i].nxt) {
        int v = G[i].v;
        if(!Dfn[v]) {
            Tarjan(v);
            Low[x] = std:: min(Low[x], Low[v]);
        } else if(vis[v]) Low[x] = std:: min(Low[x], Low[v]);
    }
    if(Dfn[x] == Low[x]) {
        vis[x] = 0, Belong[x] = ++ Scc;
        Size[Scc] = 1;
        while(Stack[topp] != x) {
            vis[Stack[topp]] = 0, Belong[Stack[topp]] = Scc;
            topp --;
            Size[Scc] ++;
        }
        topp --;
    }
}

inline void Rebuild() {
    cnt = 0;
    memset(head_2, -1, sizeof head_2);
    for(int u = 1; u <= Q; u ++)
        for(int i = head[u]; ~ i; i = G[i].nxt)
            if(Belong[u] != Belong[G[i].v]) Add_2(Belong[u], Belong[G[i].v]);
}

int Answer, tot[N];

void Dfs(int u) {
    vis[u] = 1;
    for(int i = head_2[u]; ~ i; i = E[i].nxt) {
        int v = E[i].v;
        if(!vis[v]) Dfs(v);
        tot[u] = std:: max(tot[u], tot[v]);
    }
    tot[u] += Size[u];
    Answer = std:: max(Answer, tot[u]);
}

int main() {
    Q = read(), n = read(), m = read();
    for(int i = 1; i <= Q; i ++) {
        X[i] = read(), Y[i] = read(), Opt[i] = read();
        Vecx[X[i]].push_back(i);
        Vecy[Y[i]].push_back(i);
        Map[X[i]][Y[i]] = i;
    }
    Build();
    for(int i = 1; i <= Q; i ++) if(!Dfn[i]) Tarjan(i);
    Rebuild();
    memset(vis, 0, sizeof vis);
    for(int i = 1; i <= Scc; i ++) if(!vis[i]) Dfs(i);
    std:: cout << Answer;
    return 0;
}

 

转载于:https://www.cnblogs.com/shandongs1/p/9461203.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值