[BZOJ2657][Zjoi2012]旅游(journey)(一些特殊的技巧+树的直径)

本文介绍了一种通过三角剖分将城市间的连接抽象为树结构的方法,并利用深度优先搜索(DFS)来求解该树的最大直径,以此确定任意两城市间的最大距离。文章详细解释了如何识别城市之间的相邻关系并构建相应的数据结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

由于是三角剖分,所以可以把一个城市看作一个点,将相邻的城市对连边,形成一个n2n−2个点的树,然后dfs求一遍树的直径,加11后就是答案。
而现在的关键在于怎样找出相邻的城市对
首先找到三角剖分中所有的分界线。即对于每个三角形(城市)的三边,如果这条边不在多边形的边界上,那么这条边是分界线。
然后对于每条分界线,求出这条分界线两端的城市
显然,这条分界线两端的三角形,一定包含有这条分界线作为三角形的某一边
具体地,用一个map储存包含某一条边的三角形有哪些(包含同一条边的三角形最多2个)。
这样就能求出分界线两端的城市了。建树完毕。
代码:

#include <map>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
using namespace std;
inline int read()
{
    int res = 0; bool bo = 0; char c;
    while (((c = getchar()) < '0' || c > '9') && c != '-');
    if (c == '-') bo = 1; else res = c - 48;
    while ((c = getchar()) >= '0' && c <= '9')
        res = (res << 3) + (res << 1) + (c - 48);
    return bo ? ~res + 1 : res;
}
typedef long long ll;
const int N = 2e5 + 5, M = N * 3;
int n, m, ecnt, nxt[M], adj[N], go[M], f[N], g[N], ans;
map<ll, int> fir, sec;
void add_edge(int u, int v)
{
    nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v;
    nxt[++ecnt] = adj[v]; adj[v] = ecnt; go[ecnt] = u;
}
struct cyx
{
    int u, v;
    cyx() {}
    cyx(int _u, int _v) :
        u(_u), v(_v) {}
} edge[M];
bool comp(cyx a, cyx b)
{
    if (a.u != b.u) return a.u < b.u;
    return a.v < b.v;
}
bool isnxt(int x, int y)
{
    return x + 1 == y || (x == 1 && y == n);
}
ll prod(int u, int v)
{
    return 1ll * u * (n - 1) + v;
}
void addsuf(int u, int v, int i)
{
    ll id = prod(u, v);
    if (fir[id]) sec[id] = i;
    else fir[id] = i;
}
void dfs(int u, int fu)
{
    for (int e = adj[u], v; e; e = nxt[e])
    {
        if ((v = go[e]) == fu) continue;
        dfs(v, u);
        if (f[v] + 1 > f[u]) g[u] = f[u], f[u] = f[v] + 1;
        else if (f[v] + 1 > g[u]) g[u] = f[v] + 1;
    }
}
int main()
{
    int i, x, y, z;
    n = read();
    For (i, 1, n - 2)
    {
        x = read(); y = read(); z = read();
        if (x > z) swap(x, z);
        if (y > z) swap(y, z);
        if (x > y) swap(x, y);
        if (!isnxt(x, y)) edge[++m] = cyx(x, y),
            addsuf(x, y, i);
        if (!isnxt(x, z)) edge[++m] = cyx(x, z),
            addsuf(x, z, i);
        if (!isnxt(y, z)) edge[++m] = cyx(y, z),
            addsuf(y, z, i);
    }
    sort(edge + 1, edge + m + 1, comp);
    For (i, 1, m) if (i == 1 || edge[i].u != edge[i - 1].u
        || edge[i].v != edge[i - 1].v)
        {
            ll id = prod(edge[i].u, edge[i].v);
            add_edge(fir[id], sec[id]);
        }
    dfs(1, 0);
    For (i, 1, n - 2) ans = max(ans, f[i] + g[i]);
    cout << ans + 1 << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值