ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2022杭电第二场多校 Static Query on Tree

2022-07-26 20:02:12  阅读:163  来源: 互联网

标签:int 询问 Tree 多校 dfs st 杭电 dep LCA


Problem - 7150 Static Query on Tree

题意:

给定一棵以1为根的有向树,\(q\) 次询问,每次询问给出三个集合 \(A,B,C\) 问树中满足可以由集合 \(A, B\) 中各自至少一个点走到的,自身也可以走到 \(C\) 集合中至少一个点的点的个数。

有一个比较显然的树链剖分写法,这里说的是虚树写法,其实也类似树剖写法

假设 \(q = 1\),考虑能否在 \(O(n)\) 的时间内解决问题

我们考虑,从根开始往下走,如果走到 \(C\) 集合的点,于是给该点的子树所有结点染1色,然后如果子树中有 \(A\) 集合的就染2色,有 \(B\) 集合的就染3色,最后看染齐三种颜色的点的个数即可。

于是我们考虑,当每次询问的时候应该如何解决。

注意到,每次询问的时候,我们要考虑的主要还是给定的询问点,其他点只需要知道其个数即可。所以我们只需要在原树的基础上,提取出这些关键点,然后对这些关键点建树即可。

于是剩下的问题就是建树

首先需要预处理一些信息,每个点的时间戳 \(dfn[i]\),深度 \(dep[i]\) 还有他们的公共祖先数组 \(f\),这些一次dfs就可以完成

我们在得到询问点之后,将这些询问点按照时间戳从小到大排序,设这个序列为 \(p\) 序列

考虑扩充这个序列,使得这个序列中的结点为最后虚树的所有结点

\(\forall i \in p\) 考虑加入 \(LCA(p[i], p[i - 1])\),因为是按照时间戳排序的,所以要不 \(LCA(p[i], p[i - 1]) = p[i - 1]\) 或者 \(LCA(p[i], p[i - 1]) = newP\)

考虑倒着来,因为 \(LCA(newP,p[i-2]) = LCA(p[i - 1],p[i - 2])\)

所以我们这样循环一遍就找出了所有的虚树结点

建好虚树之后,我们按照之前的想法dfs一遍即可

#include <bits/stdc++.h>
#define endl '\n'
#define ls u << 1
#define rs u << 1 | 1
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL,LL> PLL;
const int INF = 0x3f3f3f3f, N = 2e5 + 10;
const int MOD = 1e9 + 7;
const double eps = 1e-6;
const double PI = acos(-1);
inline int lowbit(int x) {return x & (-x);}

vector<int> g[N], ng[N];
int f[N][22], dep[N], dfn[N];
int stk[N], tt;
int st[N], tag[N];
int timeStamp;
int ans;

void dfs(int u) {
    dfn[u] = ++ timeStamp;
    dep[u] = dep[f[u][0]] + 1;
    for (int v : g[u]) dfs(v);
}
int LCA(int a, int b) {
    if (dep[a] < dep[b]) swap(a, b);
    for (int i = 20; ~i; i -- ) {
        if (dep[f[a][i]] >= dep[b]) a = f[a][i];
    }
    if (a == b) return a;
    for (int i = 20; ~i; i -- ) {
        if (f[a][i] != f[b][i]) a = f[a][i], b = f[b][i];
    }
    return f[a][0];
}
int getDist(int a, int b) {
    int p = LCA(a, b);
    return dep[a] + dep[b] - 2 * dep[p];
}
void calc(int u) {
    for (int v : ng[u]) {
        if (st[u] >> 2 & 1) st[v] |= 1 << 2;
        calc(v);
        if (st[v] & 1) st[u] |= 1;
        if (st[v] >> 1 & 1) st[u] |= 1 << 1;
        if (st[v] == 7) {
            ans += getDist(u, v) - 1;
        }
    }
    if (st[u] == 7) ans ++;
}
inline void solve() {
    timeStamp = 0;
    int n, m; cin >> n >> m;
    for (int i = 1; i <= n; i ++ ) {
        g[i].clear();
        dep[i] = dfn[i] = 0;
        for (int j = 0; j <= 20; j ++ ) f[i][j] = 0;
    }
    for (int i = 2; i <= n; i ++ ) {
        int x; cin >> x;
        f[i][0] = x;
        g[x].push_back(i);
    }
    dfs(1);
    for (int j = 1; j <= 20; j ++ ) {
        for (int i = 1; i <= n; i ++ ) f[i][j] = f[f[i][j - 1]][j - 1];
    }
    while (m -- ) {
        int A, B, C; cin >> A >> B >> C;
        vector<int> a(A), b(B), c(C);
        vector<int> now;
        for (int i = 0; i < A; i ++ ) {
            cin >> a[i];
            if (!st[a[i]]) now.push_back(a[i]);
            st[a[i]] |= (1 << 0);
        }
        for (int i = 0; i < B; i ++ ) {
            cin >> b[i];
            if (!st[b[i]]) now.push_back(b[i]);
            st[b[i]] |= (1 << 1);
        }
        for (int i = 0; i < C; i ++ ) {
            cin >> c[i];
            if (!st[c[i]]) now.push_back(c[i]);
            st[c[i]] |= (1 << 2);
        }

        sort(now.begin(), now.end(), [&](int x, int y) {
            return dfn[x] < dfn[y];
        });
        for (int i = (int)now.size() - 1; i; i -- ) {
            now.push_back(LCA(now[i], now[i - 1]));
        }
        sort(now.begin(), now.end(), [&](int x, int y) {
            return dfn[x] < dfn[y];
        });
        now.erase(unique(now.begin(), now.end()), now.end());
        for (int i = 1; i < now.size(); i ++ ) {
            ng[LCA(now[i - 1], now[i])].push_back(now[i]);
        }
        int root = now[0];
        calc(root);
        cout << ans << endl;
        ans = 0;
        st[1] = tag[1] = 0;
        for (auto ite : now) {
            st[ite] = tag[ite] = 0;
            ng[ite].clear();
        }
    }
}
signed main() {
#ifdef DEBUG
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
    auto now = clock();
#endif
    ios::sync_with_stdio(false), cin.tie(nullptr);
    cout << fixed << setprecision(2);
    int T; cin >> T;
    while (T -- )
        solve();
#ifdef DEBUG
    cout << "============================" << endl;
    cout << "Program run for " << (clock() - now) / (double)CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif
    return 0;
}

标签:int,询问,Tree,多校,dfs,st,杭电,dep,LCA
来源: https://www.cnblogs.com/JYF-AC/p/16522380.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有