HDU 5840 This world need more Zhu 树链剖分+暴力

This world need more Zhu

题目连接:

http://acm.hdu.edu.cn/showproblem.php?pid=5840

Description

As we all know, Zhu is the most powerful man. He has the infinite power to protest the world. We need more men like Zhu!

In Duoladuo, this place is like a tree. There are n vertices and n−1 edges. And the root is 1. Each vertex can reached by any other vertices. Each vertex has a people with value Ai named Zhu’s believer.

Liao is a curious baby, he has m questions to ask Zhu. But now Zhu is busy, he wants you to help him answer Liao’s questions.

Liao’s question will be like “u v k”.

That means Liao want to know the answer from following code:

  ans = 0; cnt = 0;

  for x in the shortest path from u to v {

    cnt++;
    
    if(cnt mod k == 0) ans = max(ans,a[x]);

  }

  print(ans).

Please read the hints for more details.

Input

In the first line contains a single positive integer T, indicating number of test case.

In the second line there are two numbers n, m. n is the size of Duoladuo, m is the number of Liao’s questions.

The next line contains n integers A1,A2,…An, means the value of ith vertex.

In the next n−1 line contains tow numbers u, v. It means there is an edge between vertex u and vertex v.

The next m lines will be the Liao’s question:

u v k

1≤T≤10,1≤n≤100000,1≤m≤100000,1≤u,v≤n,1≤k, Ai≤1000000000.

Output

For each case, output Case #i: (i is the number of the test case, from 1 to T).

Then, you need to output the answer for every Liao’s questions.

Sample Input

1
5 5
1 2 4 1 2
1 2
2 3
3 4
4 5
1 1 1
1 3 2
1 3 100
1 5 2
1 3 1

Sample Output

Case #1:
1
2
0
2
4

Hint

题意

给你一棵树,然后Q次询问,每个询问给你u,v,k,问你从u到v,每次跳k步,然后路过的最大值是多少。

题解:

k大的时候,肯定XJB暴力就好了。

但是这个暴力也不能纯暴力呀,往上跳这个玩意儿得做到O1才行。

这个你就按照dfs序的顺序去维护就好了,然后下标减去k,就表示这个点往上跳了k步。

K小的时候,XJB暴力就不行了,这个就得机智一点。

我们考虑询问,其实可以把询问拆成两个,u到lca(u,v)中,deep%k=a的最大值,和v到lca(u,v)中,deep%k=b的最大值。

询问拆开之后,我们对于熟练剖分之后,把所有点%k等于相同值的点扔在一起,然后就相当于我们拆成了k棵树,每棵树的形态都是一样的。

然后我们随便拿一颗线段树莽一波就好了。

至于为什么我的块是20,大概是因为前面瞎JB暴力的常数比树链剖分的常数低吧?

【其实大概是傻逼出题人出的数据太TM水了吧?

代码

#include <bits/stdc++.h>
#define ls (o << 1)
#define rs (o << 1 | 1)
#define FI first
#define SE second
using namespace std;

const int N = 100005;

const int MAGIC = 20;

int a[N];

vector <int> G[N];

int seq[N], tin[N], fa[N], dep[N], top[N], son[N], sz[N], label;

void dfs1(int u, int father) {
    fa[u] = father;
    son[u] = 0; sz[u] = 1;
    for(auto v : G[u]) {
        if(v == father) continue;
        dep[v] = dep[u] + 1;
        dfs1(v, u);
        sz[u] += sz[v];
        if(sz[v] > sz[son[u]])
            son[u] = v;
    }
}

void dfs2(int u, int anc) {
    top[u] = anc; tin[u] = ++ label;
    seq[label] = u;
    if(son[u]) dfs2(son[u], anc);
    for(auto v : G[u]) {
        if(v == fa[u] || v == son[u])
            continue;
        dfs2(v, v);
    }
}

inline int lca(int u, int v) {
    while(top[u] ^ top[v]) {
        if(dep[top[u]] < dep[top[v]]) swap(u, v);
        u = fa[top[u]];
    }
    return dep[u] < dep[v] ? u : v;
}

vector < pair < pair <int, int>, int> > qs[MAGIC + 5];

int n, m, ans[N];

int nS[N], cL[N], cR[N];

struct Seg {
    int l, r, v;
} T[N << 2];

void build(int o, int l, int r) {
    T[o].l = l; T[o].r = r;
    if(l == r) { T[o].v = a[seq[nS[l]]]; return; }
    int mid = (l + r) >> 1;
    build(ls, l, mid);
    build(rs, mid + 1, r);
    T[o].v = max(T[ls].v, T[rs].v);
}

int query(int o, int l, int r) {
    if(T[o].l == l && T[o].r == r) return T[o].v;
    int mid = (T[o].l + T[o].r) >> 1;
    if(r <= mid) return query(ls, l, r);
    if(l > mid) return query(rs, l, r);
    return max(query(ls, l, mid), query(rs, mid + 1, r));
}

inline int cal(int l, int r, int k) {
    if(cL[k] > cR[k]) return 0;
    l = lower_bound(nS + cL[k], nS + cR[k] + 1, l) - nS;
    r = upper_bound(nS + cL[k], nS + cR[k] + 1, r) - nS - 1;
    return l <= r ? query(1, l, r) : 0;
}

int ask(int u, int v, int k) {
    int ret = -1, f = lca(u, v);
    int uk = (dep[u] + 1) % k;
    int vk = (dep[f] + (k - (dep[u] - dep[f] + 1) % k)) % k;
    while(top[u] ^ top[v]) {
        if(dep[top[u]] > dep[top[v]]) {
            ret = max(ret, cal(tin[top[u]], tin[u], uk));
            u = fa[top[u]];
        } else {
            ret = max(ret, cal(tin[top[v]], tin[v], vk));
            v = fa[top[v]];
        }
    }
    if(dep[u] > dep[v]) {
        ret = max(ret, cal(tin[v], tin[u], uk));
    } else {
        ret = max(ret, cal(tin[u], tin[v], vk));
    }
    return ret;
}

vector <int> E[MAGIC];

void small_case(int k) {
    for(int i = 1; i <= n; ++ i) {
        int u = seq[i];
        E[dep[u] % k].push_back(u);
    }
    label = 0;
    for(int i = 0; i < k; ++ i) {
        cL[i] = label + 1;
        for(auto x : E[i])
            nS[++ label] = tin[x];
        cR[i] = label;
    }
    build(1, 1, n);
    for(auto &x : qs[k])
        ans[x.SE] = ask(x.FI.FI, x.FI.SE, k);
    for(int i = 0; i < k; ++ i)
        E[i].clear();
    qs[k].clear();
}

vector < pair < pair <int, int>, pair <int, int> > > qy[N];

int sk[N], tp;

void dfs(int u) {
    sk[++ tp] = u;
    for(auto &x : qy[u]) {
        for(int i = tp - x.FI.SE; i > 0 && dep[sk[i]] >= dep[x.FI.FI]; i -= x.SE.FI)
            ans[x.SE.SE] = max(ans[x.SE.SE], a[sk[i]]);
    }
    qy[u].clear();
    for(auto v : G[u])
        if(v ^ fa[u])
            dfs(v);
    -- tp;
}

int main() {
    int T, cas = 1;
    scanf("%d", &T);
    while(T --) {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; ++ i) {
            scanf("%d", a + i);
        }
        for(int u, v, i = 1; i < n; ++ i) {
            scanf("%d%d", &u, &v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        memset(ans, 0, m * sizeof(int));
        label = 0;
        dfs1(1, 1); dfs2(1, 1);
        for(int i = 0; i < m; ++ i) {
            int u, v, k;
            scanf("%d%d%d", &u, &v, &k);
            if(k >= MAGIC) {
                int f = lca(u, v), d = (dep[u] + dep[v] - 2 * dep[f] + 1) % k;
                if(u ^ f) qy[u].push_back( { {f, k - 1}, {k, i} } );
                if(v ^ f) qy[v].push_back( { {f, d}, {k, i} } );
            } else {
                qs[k].push_back( { {u, v}, i } );
            }
        }
        for(int i = 1; i < MAGIC; ++ i)
            if(qs[i].size())
                small_case(i);
        tp = 0; dfs(1);
        printf("Case #%d:\n", cas ++);
        for(int i = 0; i < m; ++ i)
            printf("%d\n", ans[i]);
        for(int i = 1; i <= n; ++ i)
            G[i].clear();
    }
    return 0;
}
    原文作者:qscqesze
    原文地址: https://www.cnblogs.com/qscqesze/p/5771295.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞