hdu 4822 Tri-war(LCA倍增)

题目链接

给出一棵树, n,3n105 ,然后 m1m105 ,时限是10000ms,显然每次讯问要控制在log级。
每次讯问给出a,b,c三个不同的点,对于每个点求出树上的点到它的距离严格小于到其他两个点的距离的个数。
如果是两个点,可以找到两个点的路径中点,把树分成分别包含a,b的两颗子树。三个点的话,看成ab形成的含a的子树与ac形成的含a的子树的交集,
此时就是确定ab中点与ac中点的位置关系来判断对于a的结果。

const int maxn = 1e5 + 123;
const int LOGN = 20;
int n, q;
int head[maxn], pnt[maxn*4], nxt[maxn*2], ecnt;
inline void addedge(int u,int v) {
    pnt[ecnt] = v, nxt[ecnt] = head[u], head[u] = ecnt++;
    pnt[ecnt] = u, nxt[ecnt] = head[v], head[v] = ecnt++;
}
int dep[maxn], size[maxn], fa[LOGN][maxn];
void dfs_size(int u,int f, int depth) {
    dep[u] = depth;size[u] = 1;fa[0][u] = f;
    for (int i = head[u];~i;i = nxt[i]) {
        int v = pnt[i];
        if (v != f) {
            dfs_size(v, u, depth + 1);
            size[u] += size[v];
        }
    }
    return ;
}
inline void Build_LCA() {
    for (int k = 0;k < LOGN - 1;++k) {
        for (int u = 1;u <= n;++u) {
            if (fa[k][u] == -1) fa[k + 1][u] = -1;
            else fa[k + 1][u] = fa[k][ fa[k][u] ];
        }
    }
}
inline int up(int x,int d) {
    for (int k = 0;k < LOGN - 1;++k) {
        if ((d >> k) & 1) x = fa[k][x];
    }
    return x;
}
inline int LCA(int x, int y) {
    if (dep[x] < dep[y]) swap(x, y);/*dep[x] >= dep[y]*/
    x = up(x, dep[x] - dep[y]);
    if (x == y) return x;
    for (int k = LOGN - 1;k >= 0;--k) {
        if (fa[k][x] != fa[k][y]) {
            x = fa[k][x];
            y = fa[k][y];
        }
    }
    return fa[0][x];
}
struct Node {
    int kind, x;
    Node() {}
    Node(int kind, int x) : kind(kind), x(x) {}
};
Node GetMid(int a,int b) {
    int len = dep[a] + dep[b] - 2 * dep[LCA(a, b)];
    if (dep[a] >= dep[b]) {
        /*1表明a比b深,所以其中点x在a与LCA(a,b)之间*/
        return Node(1, up(a, (len - 1) / 2));
    }else return Node(-1, up(b, len / 2));
}
/*就三种情况,画下图就能明白下面的三个判断*/
inline int Calc(int a, int b, int c) {
    Node tab = GetMid(a, b), tac = GetMid(a, c);
    if (tab.kind == 1 && tac.kind == 1) {
        if (dep[tab.x] < dep[tac.x]) swap(tab, tac); 
        if (LCA(tab.x, tac.x) == tac.x) return size[tab.x];
    }
    else if (tab.kind == -1 && tac.kind == -1) {
        if (dep[tab.x] < dep[tac.x]) swap(tab, tac);
        if (LCA(tab.x, tac.x) == tac.x) return n - size[tac.x];
        return n - size[tab.x] - size[tac.x];
    }else {
        if (tab.kind == -1) swap(tab, tac);
        if (LCA(tab.x, tac.x) == tab.x) return size[tab.x] - size[tac.x];
        return size[tab.x];
    }
}
int main(int argc, const char * argv[])
{    
    // freopen("in.txt","r",stdin);
    // freopen("out.txt","w",stdout);
    // ios::sync_with_stdio(false);
    // cout.sync_with_stdio(false);
    // cin.sync_with_stdio(false);

    int kase;read(kase);
    while(kase--) {
        read(n);
        // memset(head + 1, -1, n * sizeof (int)), ecnt = 0;/*man*/
        memset(head, -1, sizeof head), ecnt = 0;/*kuai*/
        int u, v;
        Rep(i, 1, n - 1) {
            // scanf("%d%d", &u, &v);
            read(u), read(v);
            addedge(u, v);
        }
        dfs_size(1, -1, 0);/*u, f, depth*/
        Build_LCA();/*Initiation LCA*/
        read(q);
        while(q--) {
            int a, b, c;
            // scanf("%d%d%d", &a, &b, &c);
            read(a), read(b), read(c);
            printf("%d %d %d\n", Calc(a, b, c), Calc(b, a, c), Calc(c, a, b));
        }
    }

    // showtime;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/KIJamesQi/article/details/52694085