AcWing355ダブルLCA

題名

ポータルAcWing355ビジョンストーン

回答

DFSツリーDFSD F S、各ノードのタイムスタンプを見つけます。考えてみましょうDFS DFSをD F Sのプロセス、隣接するタイムスタンプのノードdfn [x] = k、dfn [y] = k + 1 dfn [x] = k、dfn [y] = k + 1d f n [ x ]=k d f n [ y ]=k+1は常に前のノードxxですxlca(x、y)に戻りますlca(x、y)l c a x y そしてyyに再帰しますおよび

よく考えてみると、異常な石が現れるノードをタイムスタンプの小さいものから大きいものの順に円(端に近い)に配置し、隣接する2つのノード間のパス長を合計するとわかります。 、最終結果が得られます。要求された回答のちょうど2倍。

次に、STLセットを使用できますSTL \ setS T L s e t は、タイムスタンプO(log⁡N)O(\ log N)の順序で異常石の外観を維持します。O lo gN 異常な石を加算または減算する操作に対応する寄与を処理します。ツリーで乗算してLCALCAを解きますL C A、则x、yx、yx y間のパスの長さはdist(x)+ dist(y)−2×dist [lca(x、y)] dist(x)+ dist(y)-2 \ times dist [lca(x、y)]d i s t x +d i s t y 2××d i s t [ l c a x y ]合計時間計算量O((N + M)log⁡N)O((N + M)\ log N)O N+M lo gN

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
const int maxn = 100005, maxlg = 18;
int N, M, num, dfn[maxn], lg[maxn], dep[maxn], fa[maxn][maxlg];
int tot, head[maxn], to[maxn << 1], cost[maxn << 1], nxt[maxn << 1];
ll sum, ds[maxn];
set<P> st;

inline void add(int x, int y, int z)
{
    
    
    to[++tot] = y, cost[tot] = z, nxt[tot] = head[x], head[x] = tot;
}

void dfs(int x, int f, int d, ll w)
{
    
    
    dfn[x] = ++num, dep[x] = d, ds[x] = w, fa[x][0] = f;
    for (int k = 1; k <= lg[d]; ++k)
        fa[x][k] = fa[fa[x][k - 1]][k - 1];
    for (int i = head[x]; i; i = nxt[i])
    {
    
    
        int y = to[i], z = cost[i];
        if (y != f)
            dfs(y, x, d + 1, w + z);
    }
}

int lca(int x, int y)
{
    
    
    if (dep[x] < dep[y])
        swap(x, y);
    while (dep[x] > dep[y])
        x = fa[x][lg[dep[x] - dep[y]]];
    if (x == y)
        return x;
    for (int k = lg[dep[x]]; k >= 0;)
        if (fa[x][k] != fa[y][k])
            x = fa[x][k], y = fa[y][k], k = lg[dep[x]];
        else
            --k;
    return fa[x][0];
}

inline ll dist(int x, int y)
{
    
    
    return ds[x] + ds[y] - (ds[lca(x, y)] << 1);
}

inline void add(int x)
{
    
    
    st.insert(P(dfn[x], x));
    auto m = st.find(P(dfn[x], x)), l = m, r = m;
    l = l == st.begin() ? --st.end() : --l;
    r = r == --st.end() ? st.begin() : ++r;
    int a = (*l).second, b = (*m).second, c = (*r).second;
    sum -= dist(a, c);
    sum += dist(a, b) + dist(b, c);
}

inline void del(int x)
{
    
    
    auto m = st.find(P(dfn[x], x)), l = m, r = m;
    l = l == st.begin() ? --st.end() : --l;
    r = r == --st.end() ? st.begin() : ++r;
    int a = (*l).second, b = (*m).second, c = (*r).second;
    sum -= dist(a, b) + dist(b, c);
    sum += dist(a, c);
    st.erase(P(dfn[x], x));
}

int main()
{
    
    
    scanf("%d", &N);
    for (int i = 1, x, y, z; i < N; ++i)
        scanf("%d%d%d", &x, &y, &z), add(x, y, z), add(y, x, z);
    lg[0] = -1;
    for (int i = 1; i < N; ++i)
        lg[i] = lg[i - 1] + (i == (1 << (lg[i - 1] + 1)));
    dfs(1, 0, 0, 0);
    scanf("%d", &M);
    while (M--)
    {
    
    
        char op;
        int x;
        scanf(" %c", &op);
        if (op == '+' || op == '-')
            scanf("%d", &x), op == '+' ? add(x) : del(x);
        else
            printf("%lld\n", sum >> 1);
    }
    return 0;
}

おすすめ

転載: blog.csdn.net/neweryyy/article/details/114707563