Fantastic ideas of [vijos]lxhgww (long chain split)

Keywords: C++

meaning of the title

Title Link

Sol

Long chain partition

It's also a kind of violence optimized by various fancy techniques

Its main idea is: for each node, the deepest child node is regarded as the heavy son, and the edge between them is regarded as the heavy edge

It's going to have some very good light weight

  • The sum of all chain lengths is $O(n) $level

  • The subtree depth of the $k $level ancestor of any point $\ geqslant k$

First of all, we maintain what are $len[i] $nodes up each heavy chain head, and what are $len[i] $nodes down the heavy chain

$len[i] $indicates the length of the heavy chain of the node

At the same time, preprocess the multiplication array to find the ancestor

For each query, first find the first binary bit of $k $(assumed to be $r $), use the multiplication array to jump up $2^r $, and then combine the array corresponding to the processed heavy chain head to judge

Time complexity:

Preprocess multiply array complexity to $O(nlogn)$

The first bit complexity of preprocessing each number is $O(n)$

$O(1) per query$

Total complexity is $O(nlogn + m)$

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 3e5 + 10;
inline int read() {
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
int N, md[MAXN], dep[MAXN], fa[MAXN][21], son[MAXN], top[MAXN], len[MAXN], B[MAXN];
vector<int> v[MAXN], U[MAXN], D[MAXN];//up and down
void dfs(int x, int _fa) {
    md[x] = dep[x] = dep[_fa] + 1;  fa[x][0] = _fa;
    for(int i = 1; i < 20; i++) 
        if(fa[x][i - 1]) fa[x][i] = fa[fa[x][i - 1]][i - 1];
        else break;
    for(int i = 0, to; i < v[x].size(); i++) {
        if((to = v[x][i]) == _fa) continue;
        dfs(to, x); 
        if(md[to] > md[son[x]]) son[x] = to, md[x] = md[to];
    }
} 
void dfs2(int x, int topf) {
    top[x] = topf; len[x] = md[x] - dep[topf] + 1;
    if(!son[x]) return ;
    dfs2(son[x], topf);
    for(int i = 0, to; i < v[x].size(); i++) 
        if(!top[(to = v[x][i])]) dfs2(to, to);
}
void Pre() {
    int now = 0;
    for(int i = 1; i <= N; i++) {
        if(!(i & (1 << now))) now++;
        B[i] = now;
    }
    for(int i = 1; i <= N; i++) {
        if(i == top[i]) {
            for(int j = 1, x = i; j <= len[i] && x; j++) x = fa[x][0], U[i].push_back(x);
            for(int j = 1, x = i; j <= len[i] && x; j++) x = son[x], D[i].push_back(x); 
        }
    }
}
int Query(int x, int k) {
    if(k > dep[x]) return 0;
    if(k == 0) return x;
    x = fa[x][B[k]]; k ^= 1 << B[k]; 
    if(!k) return x;
    if(dep[x] - dep[top[x]] == k) return top[x];
    if(dep[x] - dep[top[x]] < k) return U[top[x]][k - dep[x] + dep[top[x]] - 1];
    else return D[top[x]][dep[x] - dep[top[x]] - k - 1];
}
int main() {
    N = read();
    for(int i = 1; i <= N - 1; i++) {
        int x = read(), y = read();
        v[x].push_back(y); v[y].push_back(x);
    }
    dfs(1, 0); dfs2(1, 1);
    Pre();
    int lastans = 0, Q = read();
    while(Q--) {
        int x = read() ^ lastans, y = read() ^ lastans;
        printf("%d\n", lastans = Query(x, y));
    }
    return 0;
}

Posted by bljepp69 on Mon, 23 Dec 2019 08:04:19 -0800