51nod1766 树上的最远点对

 

[传送门]

欧拉序可以 $O(1)$ 得到两点的 LCA

线段树维护区间直径,两个区间合并时,新的直径的端点肯定是这两个子区间直径的端点。

复杂度 $O(nlogn)$

#include 
#include 
#include 
#include 
#include 

inline void checkmax(int &a, int b) { if (a < b) a = b; }
inline void checkmin(int &a, int b) { if (a > b) a = b; }

namespace IO
{
    char buf[1 << 21], buf2[1 << 21], a[20], *p1 = buf, *p2 = buf, hh = '\n';
    int p, p3 = -1;
    void read() {}
    void print() {}
    inline int getc() {
        return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++;
    }
    inline void flush() {
        fwrite(buf2, 1, p3 + 1, stdout), p3 = -1;
    }
    template 
    inline void read(T &x, T2 &... oth) {
        T f = 1; x = 0;
        char ch = getc();
        while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getc(); }
        while (isdigit(ch)) { x = x * 10 + ch - 48; ch = getc(); }
        x *= f;
        read(oth...);
    }
    template 
    inline void print(T x, T2... oth) {
        if (p3 > 1 << 20) flush();
        if (x < 0) buf2[++p3] = 45, x = -x;
        do {
            a[++p] = x % 10 + 48;
        } while (x /= 10);
        do {
            buf2[++p3] = a[p];
        } while (--p);
        buf2[++p3] = hh;
        print(oth...);
    }
} // using namespace IO
#define read IO::read
#define print IO::print
#define flush IO::flush
#define pii pair
#define fi first
#define se second

const int N = 2e5 + 7;
const int sz = 20;
int n, tol, dfn[N], in[N], out[N], dep[N];
int st[N][sz], lg[N];
std::vector vec[N];

void dfs(int u, int pre = 0) {
    dfn[++tol] = u;
    in[u] = tol;
    for (auto p: vec[u]) {
        int v = p.fi;
        if (v == pre) continue;
        dep[v] = dep[u] + p.se;
        dfs(v, u);
        dfn[++tol] = u;
    }
    out[u] = tol;
}

void init() {
    for (int i = 2, j = 0; i <= tol; i++)
        lg[i] = ((1 << (j + 1)) == i) ? ++j : j;
    for (int i = 1; i <= tol; i++)
        st[i][0] = i;
    for (int j = 1; (1 << j) <= tol; j++)
        for (int i = 1; i + (1 << j) - 1 <= tol; i++)
            st[i][j] = dep[dfn[st[i][j - 1]]] < dep[dfn[st[i + (1 << (j - 1))][j - 1]]] ? st[i][j - 1] : st[i + (1 << (j - 1))][j - 1];
}

inline int lca(int u, int v) {
    int x = in[u], y = in[v];
    if (x > y) std::swap(x, y);
    int logg = lg[y - x + 1];
    int lca = (dep[dfn[st[x][logg]]] < dep[dfn[st[y - (1 << logg) + 1][logg]]]) ? dfn[st[x][logg]] : dfn[st[y - (1 << logg) + 1][logg]];
    return lca;
}

inline int getdis(int u, int v) {
    return dep[u] + dep[v] - 2 * dep[lca(u, v)];
}

struct Seg {
    #define lp p << 1
    #define rp p << 1 | 1
    int tree[N << 2], p1[N << 2], p2[N << 2];
    void pushup(int p) {
        checkmax(tree[p], tree[lp]);
        checkmax(tree[p], tree[rp]);
        int lu = p1[lp], lv = p2[lp], ru = p1[rp], rv = p2[rp];
        checkmax(tree[p], getdis(lu, ru));
        checkmax(tree[p], getdis(lu, rv));
        checkmax(tree[p], getdis(lv, ru));
        checkmax(tree[p], getdis(lv, rv));
        if (tree[p] == tree[lp])
            p1[p] = p1[lp], p2[p] = p2[lp];
        else if (tree[p] == tree[rp])
            p1[p] = p1[rp], p2[p] = p2[rp];
        else if (tree[p] == getdis(lu, ru))
            p1[p] = lu, p2[p] = ru;
        else if (tree[p] == getdis(lu, rv))
            p1[p] = lu, p2[p] = rv;
        else if (tree[p] == getdis(lv, ru))
            p1[p] = lv, p2[p] = ru;
        else 
            p1[p] = lv, p2[p] = rv;
    }
    void build(int p, int l, int r) {
        if (l == r) {
            p1[p] = p2[p] = l;
            return;
        }
        int mid = l + r >> 1;
        build(lp, l, mid);
        build(rp, mid + 1, r);
        pushup(p);
    }
    std::pii query(int p, int l, int r, int x, int y) {
        if (x <= l && y >= r) return std::pii(p1[p], p2[p]);
        int mid = l + r >> 1;
        if (x > mid) return query(rp, mid + 1, r, x, y);
        if (y <= mid) return query(lp, l, mid, x, y);
        auto pp = query(lp, l, mid, x, y), qq = query(rp, mid + 1, r, x, y);
        int len = 0;
        checkmax(len, getdis(pp.fi, pp.se));
        checkmax(len, getdis(qq.fi, qq.se));
        checkmax(len, getdis(pp.fi, qq.fi));
        checkmax(len, getdis(pp.fi, qq.se));
        checkmax(len, getdis(pp.se, qq.fi));
        checkmax(len, getdis(pp.se, qq.se));
        if (len == getdis(pp.fi, pp.se)) return pp;
        if (len == getdis(qq.fi, qq.se)) return qq;
        if (len == getdis(pp.fi, qq.fi)) return std::pii(pp.fi, qq.fi);
        if (len == getdis(pp.fi, qq.se)) return std::pii(pp.fi, qq.se);
        if (len == getdis(pp.se, qq.fi)) return std::pii(pp.se, qq.fi);
        return std::pii(pp.se, qq.se);
    }
} seg;

int main() {
    freopen("in.txt", "r", stdin);
    read(n);
    for (int i = 1, u, v, w; i < n; i++) {
        read(u, v, w);
        vec[u].push_back(std::pii(v, w));
        vec[v].push_back(std::pii(u, w));
    }
    dfs(1, 0);
    init();
    seg.build(1, 1, n);
    int m;
    read(m);
    for (int i = 1, a, b, c, d; i <= m; i++) {
        read(a, b, c, d);
        auto p1 = seg.query(1, 1, n, a, b);
        auto p2 = seg.query(1, 1, n, c, d);
        int ans = 0;
        checkmax(ans, getdis(p1.fi, p2.fi));
        checkmax(ans, getdis(p1.se, p2.se));
        checkmax(ans, getdis(p1.fi, p2.se));
        checkmax(ans, getdis(p1.se, p2.fi));
        print(ans);
    }
    flush();
    return 0;
}
View Code

 

你可能感兴趣的:(51nod1766 树上的最远点对)