其他分享
首页 > 其他分享> > Square Tree

Square Tree

作者:互联网

Square Tree

题目链接: [Square Tree](SquareTree (nowcoder.com))

题目描述:给你一棵\(n\)个节点的树,根节点为\(1\)。初始时所有结点的权值都为\(1\)。给你\(m\)次操作,每次操作给你三个数\(u , v , w\),其含义为:若节点\(x\),其子树中含从\(u\)到\(v\)的路径中的节点,则将节点\(x\)的权值乘以\(w\)。\(m\)次操作后,给\(Q\)个询问,每个询问给定一个节点编号\(x\),若节点\(x\)的权值是完全平方数,则输出YES,否则输出NO

数据范围:\(1 \leq n \leq 2 \times 10^5 , 1 \leq m \leq 2 \times 10^5 , 1 \leq Q \leq 2 \times 10^5 , 1 \leq w \leq 100\)。

思路:首先不管树上操作,先来看如何判断是否为完全平方数,显然要判断其表示成质因数乘积的形式的时候,其所有质因数的幂次是否为偶数,若是,则YES,否则NO。考虑到\(1 \leq w \leq 100\),所以我们可以将所有质因数求出来,重新编号,进行状压,因为只需要考虑奇偶性,所以乘法就变成异或运算。再来看操作是怎样完成的。

对于如图所示的一棵树,假设当前给定的操作的\(u = 4 , v = 5\),那么显然要更新两条路径:\(u \to v\)和\(lca(u , v) \to 1\)但不包括\(lca(u , v)\)。但考虑到判断平方数,对一个数乘同一个数三次和乘一次,其是否为平方数的性质不会发生改变,所以实际要对\(u \to v\) , \(lca(u ,v) \to 1\),\(lca(u , v) \to lca(u , v)\)这三条路径上的点都乘以权值,也即都与转化后的权值进行异或运算。在询问的时候,我们只需要查询该点最终值是否为\(0\)即可。对于树上链的更新,是比较明显的树链剖分。

时间复杂度:\(O(nlogn + mlog^2n + qlogn)\)

参考代码:

#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
using ll = long long;
struct segmentTree {
    int lr, rs, mid;
    ll tag;
};
const int N = 2e5 + 5;
segmentTree tree[N << 2];
unordered_map<int, int>mp;
vector<int>pri;
void pushDown(int rt) {
    if (tree[rt].tag == 0) return;
    tree[rt << 1].tag ^= tree[rt].tag;
    tree[rt << 1 | 1].tag ^= tree[rt].tag;
    tree[rt].tag = 0;
    return;
}
void buildTree(int rt, int lr, int rs) {
    tree[rt].lr = lr; tree[rt].rs = rs;
    if (lr == rs) return;
    int mid = tree[rt].mid = lr + rs >> 1;
    buildTree(rt << 1, lr, mid);
    buildTree(rt << 1 | 1, mid + 1, rs);
    return;
}
void update(int rt, int lr, int rs, ll val) {
    if (tree[rt].lr > rs || tree[rt].rs < lr) return;
    if (tree[rt].lr >= lr && tree[rt].rs <= rs) {
        tree[rt].tag ^= val;
        return;
    }
    pushDown(rt);
    if (tree[rt].mid >= lr) update(rt << 1, lr, rs, val);
    if (tree[rt].mid < rs) update(rt << 1 | 1, lr, rs, val);
    return;
}
bool query(int rt, int pos) {
    if (tree[rt].lr > pos || tree[rt].rs < pos) return false;
    if (tree[rt].lr == tree[rt].rs) return tree[rt].tag == 0;
    pushDown(rt);
    if (tree[rt].mid >= pos) return query(rt << 1, pos);
    return query(rt << 1 | 1, pos);
}

ll query1(int rt, int pos) {
    if (tree[rt].lr > pos || tree[rt].rs < pos) return -1;
    if (tree[rt].lr == tree[rt].rs) return tree[rt].tag;
    pushDown(rt);
    if (tree[rt].mid >= pos) return query(rt << 1, pos);
    return query(rt << 1 | 1, pos);
}
bool check(int x) {
    if (x == 2) return true;
    if (x % 2 == 0) return false;
    for (int i = 3; i * i <= x; i += 2) {
        if (x % i == 0) return false;
    }
    return true;
}
int cnt = 0;
void init() {
    for (int i = 2; i <= 100; ++i) {
        if (!check(i)) continue;
        mp[i] = cnt++;
        pri.push_back(i);
    }
}
vector<vector<int>>graph(N);
int a[N];
int father[N], depth[N], siz[N], son[N];
void dfs1(int u, int f) {
    father[u] = f; depth[u] = depth[f] + 1;
    siz[u] = 1;
    int maxsize = -1;
    for (auto g : graph[u]) {
        if (g == f) continue;
        dfs1(g, u);
        siz[u] += siz[g];
        if (siz[g] > maxsize) maxsize = siz[g], son[u] = g;
    }
    return;
}
int tim, dfn[N], top[N], outtime[N];
void dfs2(int u, int t) {
    dfn[u] = ++tim;
    top[u] = t;
    if (!son[u]) return;
    dfs2(son[u], t);
    for (auto g : graph[u]) {
        if (g == father[u] || g == son[u]) continue;
        dfs2(g, g);
    }
    outtime[u] = tim;
    return;
}
void updateChain(int u, int v, ll val) {
    while (top[u] != top[v]) {
        if (depth[top[u]] < depth[top[v]]) swap(u, v);
        update(1, dfn[top[u]], dfn[u], val);
        u = father[top[u]];
    }
    if (depth[u] > depth[v]) swap(u, v);
    update(1, dfn[u], dfn[v], val);
    return;
}
int f[N][20], dep[N];
void dfs(int u, int fa) {
    f[u][0] = fa;
    dep[u] = dep[fa] + 1;
    for (int i = 1; (1 << i) <= dep[u]; ++i) f[u][i] = f[f[u][i - 1]][i - 1];
    for (auto v : graph[u]) {
        if (v == fa) continue;
        dfs(v, u);
    }
    return;
}
int LCA(int u, int v) {
    if (dep[u] > dep[v]) swap(u, v);
    for (int i = 18; ~i; --i)
        if (dep[f[v][i]] >= dep[u]) v = f[v][i];
    if (u == v) return u;
    for (int i = 18; ~i; --i) {
        if (f[u][i] != f[v][i]) {
            u = f[u][i];
            v = f[v][i];
        }
    }
    return f[u][0];
}
void solve() {
    init();
    int n, m, q;
    cin >> n;
    for (int i = 1; i < n; ++i) {
        int u, v;
        cin >> u >> v;
        graph[u].push_back(v);
        graph[v].push_back(u);
    }
    dfs(1, 1);
    dfs1(1, 1);
    dfs2(1, 1);
    buildTree(1, 1, n);
    cin >> m;
    auto cal = [&](int w) {
        ll res = 0;
        for (auto p : pri) {
            if (w % p != 0) continue;
            int cnt = 0;
            while (w % p == 0) cnt++, w /= p;
            if (cnt % 2) res |= (1ll << mp[p]);
            if (w == 1) break;
        }
        return res;
    };
    for (int i = 1; i <= m; ++i) {
        int a, b, w;
        cin >> a >> b >> w;
        ll val = cal(w);
        int p = LCA(a, b);
        updateChain(a, b, val);
        updateChain(1, p, val);
        updateChain(p, p, val);
    }
    cin >> q;
    while (q--) {
        int x;
        cin >> x;
        if (query(1, dfn[x])) cout << "YES" << '\n';
        else cout << "NO" << '\n';
    }
    //for (int i = 1; i <= n; ++i) cout << query1(1, dfn[i]) << " ";
    return;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T = 1;
    //cin >> T;
    while (T--) solve();
    return 0;
}

标签:rt,Square,return,rs,int,tree,Tree,leq
来源: https://www.cnblogs.com/cherish-/p/16538416.html