CF519E A and B and Lecture Rooms

时间:2021-08-14 09:46:04

最近很颓……难题想不动……水题写不对,NOIP怕是????

考虑到树上路径的唯一性,假如这两个点的距离是个奇数,那么凉了,一定找不到一个点到这两个点的距离都相等。

判完奇数的情况可以找到这个和两个点距离相等的点,这里又要分两种情况讨论:

1、这个点刚好是$lca$。

CF519E A and B and Lecture Rooms

如图,蓝色为询问点,绿色为$lca$,黄色为$lca$到两个蓝色点路径上的第一个儿子。显然只有两个黄色点子树中的点是不满足条件的。

2、这个点是某个询问点到$lca$路径上的点。

 CF519E A and B and Lecture Rooms

绿色还是$lca$,蓝色是哪个深度较深的询问点,白色是在这两个点路径上到两个点距离相等的点,黄色是白色到蓝色路径上的第一个儿子。

此时只有白色点的子树中不包含黄色点子树的点符合要求。

然后坑点就是有可能两个询问点是一个点,这种情况输出个$n$就好了。

倍增跳一跳。

时间复杂度$O(nlogn)$。

Code:

CF519E A and B and Lecture RoomsCF519E A and B and Lecture Rooms
#include <cstdio>
#include <cstring>
using namespace std;

const int N = 1e5 + 5;
const int Lg = 20;

int n, qn, tot = 0, head[N];
int dep[N], fa[N][Lg], siz[N];

struct Edge {
    int to, nxt;
} e[N << 1];

inline void add(int from, int to) {
    e[++tot].to = to;
    e[tot].nxt = head[from];
    head[from] = tot;
}

inline void read(int &X) {
    X = 0; char ch = 0; int op = 1;
    for(; ch > '9'|| ch < '0'; ch = getchar())
        if(ch == '-') op = -1;
    for(; ch >= '0' && ch <= '9'; ch = getchar())
        X = (X << 3) + (X << 1) + ch - 48;
    X *= op;
}

inline void swap(int &x, int &y) {
    int t = x; x = y; y = t;
}

void dfs(int x, int fat, int depth) {
    fa[x][0] = fat, dep[x] = depth, siz[x] = 1;
    for(int i = 1; i <= 18; i++)
        fa[x][i] = fa[fa[x][i - 1]][i - 1];
    for(int i = head[x]; i; i = e[i].nxt) {
        int y = e[i].to;
        if(y == fat) continue;
        dfs(y, x, depth + 1);
        siz[x] += siz[y];
    }
}

inline int getLca(int x, int y) {
    if(dep[x] < dep[y]) swap(x, y);
    for(int i = 18; i >= 0; i--)
        if(dep[fa[x][i]] >= dep[y])
            x = fa[x][i];
    if(x == y) return x;
    for(int i = 18; i >= 0; i--)
        if(fa[x][i] != fa[y][i])
            x = fa[x][i], y = fa[y][i];
    return fa[x][0];
}

inline int getPos(int x, int stp) {
    int res = x;
    if(stp < 0) return res;
    for(int i = 18; i >= 0; i--)
        if((stp >> i) & 1)
            res = fa[res][i];
    return res;
}

int main() {
    read(n);
    for(int x, y, i = 1; i < n; i++) {
        read(x), read(y);
        add(x, y), add(y, x);
    } 
    dfs(1, 0, 1);
    
    read(qn);
    for(int x, y; qn--; ) {
        read(x), read(y);
        int z = getLca(x, y);
        if(dep[x] - dep[z] == dep[y] - dep[z]) {
            if(x == y) printf("%d\n", n);
            else {
                int sonx = getPos(x, dep[x] - dep[z] - 1);
                int sony = getPos(y, dep[y] - dep[z] - 1);
                printf("%d\n", n - siz[sonx] - siz[sony]);
            }
        } else {
            int dis = dep[x] + dep[y] - 2 * dep[z];
            if(dis & 1) puts("0");
            else {
                if(dep[x] < dep[y]) swap(x, y);
                int pos = getPos(x, dis / 2);
                int sonx = getPos(x, dep[x] - dep[pos] - 1);
                printf("%d\n", siz[pos] - siz[sonx]);
            }
        }
    }
    
    return 0;
}
View Code