CodeForces

来源:互联网 发布:ui设计师软件 编辑:程序博客网 时间:2024/06/14 06:43

题目链接:http://codeforces.com/problemset/problem/832/D

题目大意:一棵树上取3个点,求其它两点到一个点的点的最大重合数

解题思路:求出重合边数,重合点数就等于重合边数+1,假设是点a和点b到点c,那么重合边数=(dis(a,c)+dis(b,c)-dis(a,b))/2,因为要不断访问两个点的距离,所以考虑用Lca,先求出公共祖先,假设lca(a,b)=r,那么dis(a,b)=dep(a)-dep(r)+dep(b)-dep(r),即dep(a)+dep(b)-2*dep(r)

小结:Lca可用于树上快速求两点距离

AC代码:

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int MAXN = 100000 + 5;struct Edge{    int v, next;    Edge(int v = 0, int next = 0) :v(v), next(next) {}}edge[MAXN << 1];int head[MAXN], edgenum;int dep[MAXN << 1], tot, first[MAXN], tag[MAXN << 1];int st[MAXN << 1][30];int ans;void toInit(){    tot = 0;    memset(head, -1, sizeof(head));    edgenum = 0;}void toAdd(int u, int v){    edge[edgenum] = Edge(v, head[u]);    head[u] = edgenum++;}void toDfs(int u, int fa, int tier){    dep[++tot] = tier;    tag[tot] = u;    first[u] = tot;    for (int i = head[u];i != -1;i = edge[i].next)    {        int v = edge[i].v;        if (v == fa) continue;        toDfs(v, u, tier + 1);        dep[++tot] = tier;        tag[tot] = u;    }}void getSt(int n){    for (int i = 1;i <= n;++i)        st[i][0] = i;    for (int j = 1;1 << j <= n;++j)        for (int i = 1;i + (1 << j) - 1 <= n;++i)        {            int st1 = st[i][j - 1], st2 = st[i + (1 << j - 1)][j - 1];            st[i][j] = dep[st1] < dep[st2] ? st1 : st2;//保存最小深度的所在数组中的位置        }}int toRmq(int l, int r){    int k = 0;    while (1 << k <= r - l + 1) k++;    k--;    int st1 = st[l][k], st2 = st[r + 1 - (1 << k)][k];    return dep[st1] < dep[st2] ? st1 : st2;}int toLca(int x, int y){    x = first[x], y = first[y];    if (x > y) swap(x, y);//用于Rmq左右端点,所以要交换大小    return tag[toRmq(x, y)];//返回节点编号}int getDis(int x, int y){//因为r,x,y都是节点编号,先用first找到他们所在数组中的位置    int r = toLca(x, y);    return dep[first[x]] + dep[first[y]] - 2 * dep[first[r]];}void toSolve(int a, int b, int c){    int tmp = getDis(a, b) + getDis(a, c) - getDis(b, c);    ans = max(ans, tmp / 2);}int main(){    int n, q;    scanf("%d%d", &n, &q);    toInit();    for (int i = 2;i <= n;++i)    {        int pi;scanf("%d", &pi);        toAdd(i, pi);        toAdd(pi, i);    }    toDfs(1, 1, 0);    getSt(tot);//tot=2*n-1;    while (q--)    {        int a, b, c;        ans = 0;        scanf("%d%d%d", &a, &b, &c);        toSolve(a, b, c);        toSolve(b, a, c);        toSolve(c, a, b);        printf("%d\n", ans + 1);    }    return 0;}
原创粉丝点击