HDU - 6430 TeaTree 树上启发式合并

题意

给你一个树,每个点有个权值v[i]。

每两个点i, j会告诉他们的LCA一个值gcd(v[i], v[j])。

现在问每个点所听到的最大的值。

n <= 1e5, v[i] <= 1e5

题解

树上启发式合并。

对于每个节点,用set记录它的子树存在哪些因子, 取所有出现两次的因子的max。

要求出这个set,我们对于它所有的儿子的set,看哪个大,每次把小的一个set里的数一一插入到大的set里面去,同时判断大的set里面是否已经存在这个数,如果存在,这个节点的ans对这个数取max。

注意合并之后原来的set要clear掉,这样省空间也省时间。

还可以用unordered_set加速。

复杂度n * \sqrt{n} * \log{n} * \log{n}

代码

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <bitset>
#include <map>
#include <vector>
#include <set>

#ifdef LOCAL
#define debug(x) cout<<#x<<" = "<<(x)<<endl;
#else
#define debug(x) 1;
#endif

#define lson id<<1,l,mid
#define rson id<<1|1,mid+1,r
#define lowbit(x) x&-x
#define mp make_pair
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int MOD = 998244353;
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fll;
const int MAXN = 1e5 + 5;
const int mod = 998244353;

int f[MAXN], v[MAXN];

struct Edge {
    int v, nxt;
} e[MAXN];
int head[MAXN], tot;

void add (int x, int y) {
    e[tot] = {y, head[x]};
    head[x] = tot++;
}

int ans[MAXN];
set<int> s[MAXN];
int tran[MAXN];

void dfs (int now) {
    tran[now] = now;
    for (int i = head[now]; ~i; i = e[i].nxt) {
        dfs (e[i].v);
        if (s[tran[e[i].v]].size() < s[tran[now]].size() ) {
            for (int p : s[tran[e[i].v]]) {
                if (s[tran[now]].count (p) ) ans[now] = max (ans[now], p);
                else s[tran[now]].insert (p);
            }
            s[tran[e[i].v]].clear();
        } else {
            for (int p : s[tran[now]]) {
                if (s[tran[e[i].v]].count (p) ) ans[now] = max (ans[now], p);
                else s[tran[e[i].v]].insert (p);
            }
            s[tran[now]].clear();
            tran[now] = tran[e[i].v];
        }
    }
    for (int i = 1; i * i <= v[now]; i++) {
        if (v[now] % i == 0) {
            if (s[tran[now]].count (i) ) ans[now] = max (ans[now], i);
            else s[tran[now]].insert (i);
            if (i * i != v[now]) {
                if (s[tran[now]].count (v[now] / i) ) ans[now] = max (ans[now], v[now] / i);
                else s[tran[now]].insert (v[now] / i);
            }
        }
    }
}

int read() {
    int x = 0;
    char c = getchar();
    while (c < '0' || c > '9')c = getchar();
    while (c >= '0' && c <= '9') {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x;
}



int main() {
#ifdef LOCAL
    freopen ("input.txt", "r", stdin);
#endif
    int n;
    n = read();
    memset (head, -1, sizeof (head) );
    memset (ans, -1, sizeof (ans) );
    for (int i = 2; i <= n; i++) {
        f[i] = read();
        add (f[i], i);
    }
    for (int i = 1; i <= n; i++) v[i] = read();
    dfs (1);
    for (int i = 1; i <= n; i++) printf ("%d\n", ans[i]);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/c6376315qqso/article/details/81952276