[BZOJ1023][SHOI2008[Cactus仙人掌]][Tarjan+单调队列+树形DP]

50 篇文章 0 订阅
3 篇文章 0 订阅

[BZOJ1023][SHOI2008[Cactus仙人掌]][Tarjan+单调队列+树形DP]

题目大意:

给定一棵仙人掌,求仙人掌上最长路径。(路径要求是两点之间的最短路)

思路:

题目太神啦

好菜啊虽然过了BZOJ1040但还是一点不会做,快来看这个题解太神啦:http://z55250825.blog.163.com/blog/static/150230809201412793151890/

代码:
#include <bits/stdc++.h>
const int Maxn = 100010;
using namespace std;

inline int Max(const int &a, const int &b) {
    return a > b ? a : b;
}
inline int Min(const int &a, const int &b) {
    return a < b ? a : b;
}
namespace IO {
    inline char get(void) {
        static char buf[1000000], *p1 = buf, *p2 = buf;
        if (p1 == p2) {
            p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin);
            if (p1 == p2) return EOF;
        }
        return *p1++;
    }
    inline void read(int &x) {
        x = 0; static char c;
        for (; !(c >= '0' && c <= '9'); c = get());
        for (; c >= '0' && c <= '9'; x = x * 10 + c - '0', c = get());
    }
};
int head[Maxn], sub;
struct Edge {
    int to, nxt;
    Edge(void) {}
    Edge(const int &to, const int &nxt) : to(to), nxt(nxt) {}
} edge[20000005];
inline void add(int a, int b) {
    edge[++sub] = Edge(b, head[a]), head[a] = sub;
}
int n, m;
int fa[Maxn], low[Maxn], dfn[Maxn], FFF, dep[Maxn], f[Maxn], ans;
int a[Maxn], q[Maxn], l, r;
inline void Dp(int u, int v) {
    int tot = dep[v] - dep[u] + 1;
    for (int i = v; i != u; i = fa[i]) {
        a[tot--] = f[i];
    }
    a[tot] = f[u];
    tot = dep[v] - dep[u] + 1;
    for (int i = 1; i <= tot; i++) a[i + tot] = a[i];
    q[1] = 1; l = r = 1;
    for (int i = 2; i <= tot << 1; i++) {
        while (l <= r && i - q[l] > tot / 2) l++;
        ans = Max(ans, a[i] + i + a[q[l]] - q[l]);
        while (l <= r && a[q[r]] - q[r] <= a[i] - i) r--;
        q[++r] = i;
    }
    for (int i = 2; i <= tot; i++)
        f[u] = Max(f[u], a[i] + Min(i - 1, tot - i + 1));
}
inline void dfs(int u) {
    low[u] = dfn[u] = ++FFF;
    for (int i = head[u], v; i; i = edge[i].nxt) {
        v = edge[i].to;
        if (v == fa[u]) continue;
        if (!dfn[v]) {
            fa[v] = u;
            dep[v] = dep[u] + 1;
            dfs(v);
            low[u] = Min(low[u], low[v]);
        }
        else low[u] = Min(low[u], dfn[v]);
        if (dfn[u] < low[v]) {
            ans = Max(ans, f[u] + f[v] + 1);
            f[u] = Max(f[u], f[v] + 1);
        }
    }
    for (int i = head[u], v; i; i = edge[i].nxt) {
        v = edge[i].to;
        if (fa[v] != u && dfn[u] < dfn[v]) Dp(u, v);
    }
}
int main(void) {
    //freopen("in.txt", "r", stdin);
    IO::read(n); IO::read(m);
    int k, a, b;
    for (int i = 1; i <= m; i++) {
        IO::read(k), IO::read(a);
        for (int j = 2; j <= k; j++) {
            IO::read(b);
            add(a, b), add(b, a);
            a = b;
        }
    }
    dfs(1);

    cout << ans << endl;
    return 0;
}

完。

By g1n0st

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值