hihocoder#1065 : 全图传送

 

[传送门]

 

如果只有单组询问就是水题。多组询问就不能直接在线做了。考虑离线。

点分治,把当前重心到未被处理过的子树的距离放进一个数组,按距离从小到大排序。排完序后把这些节点替换成当前前缀权值最大的节点。因为如果到这个节点的距离为$r$,那么小于$r$的也能到达,所以取前缀max没有错。

然后对询问的距离二分一下就可以了。

#include <bits/stdc++.h>
#define pii pair<int, int>
#define pb push_back
#define fi first
#define se second
using namespace std;

const int N = 1e5 + 7;
int n, val[N], sz[N], maxsz[N], totsz, root;
bool vis[N];
vector<pii> G[N];

struct QUE {
    int u, dis;
    QUE(int u = 0, int dis = 0): u(u), dis(dis) {}
    bool operator < (const QUE& t) const { return dis < t.dis; }
} que[N];

int ans[N];
int ne[N], head[N], cnt, to[N];

void getroot(int u, int fa) {
    sz[u] = 1; maxsz[u] = 0;
    for (auto p: G[u]) {
        int v = p.se;
        if (vis[v] || v == fa) continue;
        getroot(v, u);
        sz[u] += sz[v];
        maxsz[u] = max(maxsz[u], sz[v]);
    }
    maxsz[u] = max(maxsz[u], totsz - sz[u]);
    if (maxsz[u] < maxsz[root]) root = u;
}

QUE temp[N];
int tol, x[N];

void dfs(int u, int dep, int fa) {
    temp[++tol] = QUE(u, dep);
    for (auto p: G[u]) {
        int v = p.se;
        if (vis[v] || v == fa) continue;
        dfs(v, dep + p.fi, u);
    }
}

void cal() {
    sort(temp + 1, temp + 1 + tol);
    for (int i = 1; i <= tol; i++) {
        x[i] = temp[i].u;
        if (i == 1) continue;
        if (val[temp[i].u] < val[temp[i - 1].u] || (val[temp[i].u] == val[temp[i - 1].u] && temp[i].u > temp[i - 1].u))
            temp[i].u = temp[i - 1].u;
    }
    for (int i = 1; i <= tol; i++) {
        for (int j = head[x[i]]; j; j = ne[j]) {
            QUE q = que[j];
            if (q.dis < temp[i].dis) continue;
            int pos = upper_bound(temp + 1, temp + 1 + tol, QUE(0, q.dis - temp[i].dis)) - temp;
            if (pos <= tol && q.dis - temp[i].dis >= temp[pos].dis) pos++;
            pos--;
            if (val[ans[j]] < val[temp[pos].u] || (val[ans[j]] == val[temp[pos].u] && ans[j] > temp[pos].u)) 
                ans[j] = temp[pos].u;
        }
    }
}

void solve(int u) {
    vis[u] = 1;
    tol = 0;
    dfs(u, 0, 0);
    cal();
    for (auto p: G[u]) {
        int v = p.se;
        if (vis[v]) continue;
        totsz = sz[v];
        root = 0;
        getroot(v, u);
        solve(root);
    }
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%d", &val[i]);
    for (int i = 1; i < n; i++) {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        G[u].pb(pii(w, v));
        G[v].pb(pii(w, u));
    }
    int q;
    scanf("%d", &q);
    for (int i = 1; i <= q; i++) {
        scanf("%d%d", &que[i].u, &que[i].dis);
        ne[++cnt] = head[que[i].u];
        head[que[i].u] = cnt;
        ans[i] = n + 1;
    }
    maxsz[root = 0] = n;
    totsz = n;
    getroot(1, 0);
    solve(root);
    for (int i = 1; i <= q; i++)
        printf("%d\n", ans[i]);
    return 0;
}
View Code

 

posted @ 2019-10-14 21:28  Mrzdtz220  阅读(162)  评论(0编辑  收藏  举报