題名
回答
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ですxはlca(x、y)に戻りますlca(x、y)l c a (x 、y )そしてyyに再帰しますおよび。
よく考えてみると、異常な石が現れるノードをタイムスタンプの小さいものから大きいものの順に円(端に近い)に配置し、隣接する2つのノード間のパス長を合計するとわかります。 、最終結果が得られます。要求された回答のちょうど2倍。
次に、STLセットを使用できますSTL \ setS T L s e t は、タイムスタンプO(logN)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)logN)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;
}