漂亮的公园 - 牛客

ps:再再再再次感觉自己好菜!此题有个结论:对于一棵树,给定一个点集S,设其最远的两个点为x,y。其它点u到这个点集S的最远距离,必然是到u到x的距离或者是u到y的距离。这样两个集合之间的距离就转化为4个点距离!!!!怎么求每个集合的最远的两个点呢?还是同样的方法,取该集合的两个点作为最远的两个点(直径(不是树的直径)),然后依次加入该集合的其它点,更新即可。集合的直径与如入元素的顺序无关!

const int N = 100005;

struct LCA {
    vector<int> G[N];
    int n, d[N], pa[N][20];

    void Inite(int cnt) {
        n = cnt;
        mem(pa, 0);
    }
    void addedge(int u, int v) {
        G[u].pb(v);
        G[v].pb(u);
    }
    void DFS(int u, int fa, int dep) {
        d[u] = dep;
        pa[u][0] = fa;
        for (auto v : G[u]) if (v != fa) DFS(v, u, dep + 1);
    }
    void ST() {
        DFS(1, 0, 0);
        for (int i = 1; (1 << i) <= n; ++i) {
            for (int j = 1; j <= n; ++j) if (pa[j][i - 1]) pa[j][i] = pa[pa[j][i - 1]][i - 1];
        }
    }
    int getLca(int u, int v) {
        if (d[u] > d[v]) swap(u, v);

        rep(i, 0, 20) if ((d[v] - d[u]) & (1 << i)) v = pa[v][i];
        if (u == v) return u;

        for (int i = 19; ~i; --i) if (pa[u][i] != pa[v][i]) {
            u = pa[u][i];
            v = pa[v][i];
        }
        return pa[u][0];
    }
    int computed(int u, int v) {
        int fa = getLca(u, v);
        return (d[u] + d[v] - 2 * d[fa]);
    }
};

LCA lca;

P od[N];  // 记录每个集合的直径(最远的两个点)
int n, q, tot;

vector<int> p[N];

map<int, int> c;

int main()
{
    sc(n), sc(q);
    Rep(i, 1, n) {
        int u;
        sc(u);
        if (!c[u]) c[u] = ++tot;
        p[c[u]].pb(i);
    }

    lca.Inite(n);

    rep(i, 1, n) {
        int u, v;
        sc(u), sc(v);
        lca.addedge(u, v);
    }

    lca.ST();

    Rep(i, 1, tot) {
        od[i].first = od[i].second = p[i][0];
        int last = 0;
        rep(j, 1, p[i].size()) {
            int l = lca.computed(p[i][j], od[i].first);
            int r = lca.computed(p[i][j], od[i].second);
            if (l >= r && l > last) {
                od[i].second = p[i][j];
                last = l;
            }
            else if (r >= l && r > last) {
                od[i].first = p[i][j];
                last = r;
            }
        }
    }
    while(q--) {
        int x, y, res = 0;
        sc(x), sc(y);
        if (!c[x] || !c[y]) puts("0");
        else if (c[x] == c[y]) {
            int res = lca.computed(od[c[x]].first, od[c[x]].second);
            pr(res);
        }
        else {
            int t1 = lca.computed(od[c[x]].first, od[c[y]].first);
            if (t1 > res) res = t1;
            int t2 = lca.computed(od[c[x]].first, od[c[y]].second);
            if (t2 > res) res = t2;
            int t3 = lca.computed(od[c[x]].second, od[c[y]].first);
            if (t3 > res) res = t3;
            int t4 = lca.computed(od[c[x]].second, od[c[y]].second);
            if (t4 > res) res = t4;
            pr(res);
        }
    }
    return 0;
}

 

posted @ 2018-09-13 15:07  天之道,利而不害  阅读(140)  评论(0编辑  收藏  举报