3991: [SDOI2015]寻宝游戏
3991: [SDOI2015]寻宝游戏
https://www.lydsy.com/JudgeOnline/problem.php?id=3991
分析:
虚树+set。
要求树上许多点之间的路径的总长的2倍。就是虚树。
结论:如果将所有的点按dfs序拍好,答案就是相邻点之间的路径长度的和*2。所以这个可以按dfn维护一个set,每次操作查找前驱后继。
代码:
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<cmath> 5 #include<iostream> 6 #include<cctype> 7 #include<set> 8 #include<vector> 9 #include<queue> 10 #include<map> 11 using namespace std; 12 typedef long long LL; 13 14 inline int read() { 15 int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; 16 for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; 17 } 18 19 const int INF = 1e9; 20 const int N = 100005; 21 22 int head[N], nxt[N << 1], to[N << 1], len[N << 1], En; 23 int deth[N], bel[N], siz[N], son[N], fa[N], id[N], dfn[N], TimeIndex; 24 LL dis[N]; 25 bool vis[N]; 26 LL tmp, Ans; 27 set<int> s; 28 set<int> :: iterator it; 29 30 void add_edge(int u,int v,int w) { 31 ++En; to[En] = v; len[En] = w; nxt[En] = head[u]; head[u] = En; 32 ++En; to[En] = u; len[En] = w; nxt[En] = head[v]; head[v] = En; 33 } 34 35 void dfs1(int u) { 36 deth[u] = deth[fa[u]] + 1; 37 for (int i=head[u]; i; i=nxt[i]) { 38 int v = to[i]; 39 if (v == fa[u]) continue; 40 dis[v] = dis[u] + len[i]; 41 fa[v] = u; 42 dfs1(v); 43 siz[u] += siz[v]; 44 if (!son[u] || siz[son[u]] < siz[v]) son[u] = v; 45 } 46 } 47 48 void dfs2(int u,int top) { 49 bel[u] = top; 50 dfn[u] = ++TimeIndex; id[TimeIndex] = u; 51 if (!son[u]) return ; 52 dfs2(son[u], top); 53 for (int i=head[u]; i; i=nxt[i]) { 54 int v = to[i]; 55 if (v != fa[u] && v != son[u]) dfs2(v, v); 56 } 57 } 58 59 int LCA(int u,int v) { 60 while (bel[u] != bel[v]) { 61 if (deth[bel[u]] < deth[bel[v]]) swap(u, v); 62 u = fa[bel[u]]; 63 } 64 return deth[u] < deth[v] ? u : v; 65 } 66 67 LL getdis(int x,int y) { 68 int lca = LCA(x, y); 69 return dis[x] + dis[y] - (dis[lca] * 2); 70 } 71 72 void ins(int x) { 73 int L = *(--s.lower_bound(dfn[x])); 74 int R = *(s.upper_bound(dfn[x])); 75 if (L != -INF) Ans += getdis(id[L], x); 76 if (R != INF) Ans += getdis(id[R], x); 77 if (L != -INF && R != INF) Ans -= getdis(id[L], id[R]); 78 s.insert(dfn[x]); vis[x] = 1; 79 } 80 81 void del(int x) { 82 s.erase(dfn[x]); vis[x] = 0; 83 int L = *(--s.lower_bound(dfn[x])); 84 int R = *(s.upper_bound(dfn[x])); 85 if (L != -INF) Ans -= getdis(id[L], x); 86 if (R != INF) Ans -= getdis(id[R], x); 87 if (L != -INF && R != INF) Ans += getdis(id[L], id[R]); 88 } 89 90 int main() { 91 int n = read(), Q = read(); 92 for (int i=1; i<n; ++i) { 93 int u = read(), v = read(), w = read(); 94 add_edge(u, v, w); 95 } 96 dfs1(1); 97 dfs2(1, 1); 98 99 s.insert(-INF), s.insert(INF); 100 101 while (Q--) { 102 tmp = 0; 103 int x = read(); 104 if (!vis[x]) ins(x); 105 else del(x); 106 if (s.size() > 3) { 107 it = s.begin(); 108 int L = *(++it); 109 it = s.end(); 110 int R = *(--(--it)); 111 tmp = getdis(id[L], id[R]); 112 } 113 printf("%lld\n",Ans + tmp); 114 } 115 return 0; 116 }