zoukankan      html  css  js  c++  java
  • [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

    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;
    }
  • 相关阅读:
    20145204实验反思与总结
    20145204《信息安全系统设计基础》课程总结
    家庭作业:12.18,9.13,8.25,2.62
    20145204张亚军第14周博客总结
    20145204 张亚军《信息安全系统设计基础》第13周学习总结
    SLB技术原理浅析
    jumpserver在终端修改管理员密码及新建超级用户
    批量杀掉多个pid文件中记录的pid进程, 并集成到shell脚本中
    修改daemon.json重新加载后docker无法启动问题
    Docker的配置文件 daemon.json 详解
  • 原文地址:https://www.cnblogs.com/BriMon/p/9850419.html
Copyright © 2011-2022 走看看