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;
    }
  • 相关阅读:
    关于求 p_i != i and p_i != i+1 的方案数的思考过程
    poj 3041 Asteroids 二分图最小覆盖点
    poj 1325 Machine Schedule 最小顶点覆盖
    poj 1011 Sticks 减枝搜索
    poj 1469 COURSES 最大匹配
    zoj 1516 Uncle Tom's Inherited Land 最大独立边集合(最大匹配)
    Path Cover (路径覆盖)
    hdu 3530 SubSequence TwoPoint单调队列维护最值
    zoj 1654 Place the Rebots 最大独立集转换成二分图最大独立边(最大匹配)
    poj 1466 Girls and Boys 二分图最大独立子集
  • 原文地址:https://www.cnblogs.com/BriMon/p/9850419.html
Copyright © 2011-2022 走看看