【bzoj3991】[SDOI2015]寻宝游戏 树链的并+STL-set
生活随笔
收集整理的這篇文章主要介紹了
【bzoj3991】[SDOI2015]寻宝游戏 树链的并+STL-set
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目描述
給出一棵樹,初始每個點都是非必經的。多次改變某個點的必經狀態,并詢問從任意一個點出發,經過所有必經的點并回到該點的最小路程。
輸入
第一行,兩個整數N、M,其中M為寶物的變動次數。
接下來的N-1行,每行三個整數x、y、z,表示村莊x、y之間有一條長度為z的道路。 接下來的M行,每行一個整數t,表示一個寶物變動的操作。若該操作前村莊t內沒有寶物,則操作后村莊內有寶物;若該操作前村莊t內有寶物,則操作后村莊內沒有寶物。輸出
M行,每行一個整數,其中第i行的整數表示第i次操作之后玩家找到所有寶物需要行走的最短路程。若只有一個村莊內有寶物,或者所有村莊內都沒有寶物,則輸出0。
樣例輸入
4 5
1 2 30
2 3 50
2 4 60
2
3
4
2
1
樣例輸出
0
100
220
220
280
題解
樹鏈的并+STL-set
考慮指定某個點為根,如果從根節點出發的話,答案顯然是所有必經點到根節點的樹鏈的并的長度*2。
我們維護這個樹鏈的并:把所有點按照dfs序排序,每個點到根的距離減去排序后相鄰兩點LCA到根的距離就是樹鏈的并的長度。本題由于需要支持插入和刪除,因此可以使用STL-set。
但是這并不是最優解。考慮重復經過了哪一段:所有相鄰兩點LCA中深度最小的到根節點的距離。也即按dfs序排序后第一個點和最后一個點的LCA到根節點的距離。因此再使用set統計一下答案即可。
時間復雜度 $O(n\log n)$
#include <set> #include <cstdio> #define N 100010 using namespace std; typedef long long ll; set<int> s; int head[N] , to[N << 1] , len[N << 1] , next[N << 1] , cnt , fa[N][20] , deep[N] , log[N] , pos[N] , ref[N] , tot , vis[N]; ll dis[N]; inline void add(int x , int y , int z) {to[++cnt] = y , len[cnt] = z , next[cnt] = head[x] , head[x] = cnt; } void dfs(int x) {int i;pos[x] = ++tot , ref[tot] = x;for(i = 1 ; (1 << i) <= deep[x] ; i ++ ) fa[x][i] = fa[fa[x][i - 1]][i - 1];for(i = head[x] ; i ; i = next[i])if(to[i] != fa[x][0])fa[to[i]][0] = x , deep[to[i]] = deep[x] + 1 , dis[to[i]] = dis[x] + len[i] , dfs(to[i]); } inline int lca(int x , int y) {int i;if(deep[x] < deep[y]) swap(x , y);for(i = log[deep[x] - deep[y]] ; ~i ; i -- )if((1 << i) <= deep[x] - deep[y])x = fa[x][i];if(x == y) return x;for(i = log[deep[x]] ; ~i ; i -- )if((1 << i) <= deep[x] && fa[x][i] != fa[y][i])x = fa[x][i] , y = fa[y][i];return fa[x][0]; } int main() {int n , m , i , x , y , z;set<int>::iterator it;ll now = 0;scanf("%d%d" , &n , &m);for(i = 2 ; i <= n ; i ++ ) scanf("%d%d%d" , &x , &y , &z) , add(x , y , z) , add(y , x , z) , log[i] = log[i >> 1] + 1;dfs(1);while(m -- ){scanf("%d" , &x) , y = z = 0;if(!vis[x]){it = s.upper_bound(pos[x]);if(it != s.end()) y = ref[*it];if(it != s.begin()) z = ref[*--it];if(y) now -= dis[lca(x , y)];if(z) now -= dis[lca(x , z)];if(y && z) now += dis[lca(y , z)];now += dis[x] , vis[x] = 1 , s.insert(pos[x]);}else{now -= dis[x] , vis[x] = 0 , s.erase(pos[x]);it = s.upper_bound(pos[x]);if(it != s.end()) y = ref[*it];if(it != s.begin()) z = ref[*--it];if(y) now += dis[lca(x , y)];if(z) now += dis[lca(x , z)];if(y && z) now -= dis[lca(y , z)];}if(s.size() < 2) puts("0");else printf("%lld\n" , (now - dis[lca(ref[*s.begin()] , ref[*--s.end()])]) << 1);}return 0; }?
?
轉載于:https://www.cnblogs.com/GXZlegend/p/8059408.html
總結
以上是生活随笔為你收集整理的【bzoj3991】[SDOI2015]寻宝游戏 树链的并+STL-set的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Uva 1025 - A Spy in
- 下一篇: BZOJ 1018: [SHOI2008