[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;
}

 

posted @ 2018-10-25 15:59  zZhBr  阅读(195)  评论(0编辑  收藏  举报