3991: [SDOI2015]寻宝游戏
3991: [SDOI2015]尋寶游戲
Time Limit:?40 Sec??Memory Limit:?128 MBSubmit:?1025??Solved:?508
[Submit][Status][Discuss]
Description
?小B最近正在玩一個尋寶游戲,這個游戲的地圖中有N個村莊和N-1條道路,并且任何兩個村莊之間有且僅有一條路徑可達。游戲開始時,玩家可以任意選擇一個村莊,瞬間轉移到這個村莊,然后可以任意在地圖的道路上行走,若走到某個村莊中有寶物,則視為找到該村莊內的寶物,直到找到所有寶物并返回到最初轉移到的村莊為止。小B希望評測一下這個游戲的難度,因此他需要知道玩家找到所有寶物需要行走的最短路程。但是這個游戲中寶物經常變化,有時某個村莊中會突然出現寶物,有時某個村莊內的寶物會突然消失,因此小B需要不斷地更新數據,但是小B太懶了,不愿意自己計算,因此他向你求助。為了簡化問題,我們認為最開始時所有村莊內均沒有寶物
Input
?第一行,兩個整數N、M,其中M為寶物的變動次數。
接下來的N-1行,每行三個整數x、y、z,表示村莊x、y之間有一條長度為z的道路。 接下來的M行,每行一個整數t,表示一個寶物變動的操作。若該操作前村莊t內沒有寶物,則操作后村莊內有寶物;若該操作前村莊t內有寶物,則操作后村莊內沒有寶物。Output
?M行,每行一個整數,其中第i行的整數表示第i次操作之后玩家找到所有寶物需要行走的最短路程。若只有一個村莊內有寶物,或者所有村莊內都沒有寶物,則輸出0。
Sample Input
4 51 2 30
2 3 50
2 4 60
2
3
4
2
1
Sample Output
0100
220
220
280
HINT
?1<=N<=100000
1<=M<=100000
對于全部的數據,1<=z<=10^9
Source
Round 1 感謝yts1999上傳
[Submit][Status][Discuss]
每次修改結束后,對于當前確定的關鍵點,全部拿出來做成虛樹
要使答案最優,肯定是虛樹上每條邊走兩邊,權值和就是答案了
其實可以這樣,把所有關鍵點按照dfs序排好,只要按照dfs序一個個走過去,最后走回來就行了
這樣隨便上一個什么數據結構就行了
茍蒻選了替罪羊樹。。。。假裝是為了學習刪除操作吧。。?結果弄了好久
替罪羊樹的刪除倒是挺奇葩,不會真的把節點抹去,而是給它打個標記,代表它已經不存在了
不過節點仍然存在樹中,只是查詢操作時不把它記入答案
當一個節點內已經被刪除的節點超過一半的時候,就把這個子樹暴力重建
復雜度仍然是均攤O(nlogn)
#include<iostream> #include<cstring> #include<vector> #include<algorithm> #include<cstdio> using namespace std;typedef double DB; typedef long long LL; const DB alpha = 0.666; const DB belta = 0.500; const int maxn = 1E5 + 10; const int T = 18;struct E{int to,w; E(){}E(int to,int w): to(to),w(w){} };int n,m,dfs_clock,rt,a,tp,cnt,ch[maxn][2],dfn[maxn],fa[maxn],L[maxn],stk[maxn],Fa[maxn][T],siz[maxn],sz[maxn]; LL Ans,dis[maxn]; bool bo[maxn],ext[maxn];vector <E> v[maxn];void Dfs(int x,int from) {dfn[x] = ++dfs_clock;for (int i = 1; i < T; i++) Fa[x][i] = Fa[Fa[x][i-1]][i-1];for (int i = 0; i < v[x].size(); i++){E e = v[x][i];if (e.to == from) continue;dis[e.to] = dis[x] + 1LL * e.w;L[e.to] = L[x] + 1; Fa[e.to][0] = x; Dfs(e.to,x);} }int maintain(const int &x) {sz[x] = ext[x] ? 0 : 1;sz[x] += sz[ch[x][0]] + sz[ch[x][1]];siz[x] = 1 + siz[ch[x][0]] + siz[ch[x][1]]; } bool Judge(const int &x) {return max(siz[ch[x][0]],siz[ch[x][1]]) >= alpha * (DB)(siz[x]) || sz[x] >= belta * (DB)(siz[x]);}void Insert(int &x,int y) {if (x == y) {ext[x] = 1; maintain(x); return;}if (!x){x = y; ext[x] = siz[x] = 1;ch[x][0] = ch[x][1] = 0; maintain(x); return;}int d = dfn[x] > dfn[y] ? 0 : 1;Insert(ch[x][d],y); fa[ch[x][d]] = x;maintain(x); if (Judge(x)) a = x; }void Remove(int x,int y) {if (x == y){ext[x] = 0; maintain(x);if (Judge(x)) a = x; return;}int d = dfn[x] > dfn[y] ? 0 : 1;Remove(ch[x][d],y); maintain(x);if (Judge(x)) a = x; }int Rank(int x,int y) {if (x == y) return siz[ch[x][0]] - sz[ch[x][0]] + ext[x];int d = dfn[x] > dfn[y] ? 0 : 1,ret = 0;if (d == 1) ret = (siz[ch[x][0]] - sz[ch[x][0]] + ext[x]);return ret + Rank(ch[x][d],y); }int Find(int x,int k) {int tmp = siz[ch[x][0]] - sz[ch[x][0]] + ext[x];if (ext[x] && tmp == k) return x;int d = tmp < k ? 1 : 0; if (d) k -= tmp;return Find(ch[x][d],k); }void Dfs2(int x) {if (!x) return; Dfs2(ch[x][0]);if (ext[x]) stk[++tp] = x; Dfs2(ch[x][1]); }int Build(int l,int r) {if (l > r) return 0;int mid = (l + r) >> 1,ret = stk[mid];ch[ret][0] = Build(l,mid-1);ch[ret][1] = Build(mid+1,r);for (int i = 0; i < 2; i++)if (ch[ret][i]) fa[ch[ret][i]] = ret;maintain(ret); return ret; }void Rebuild(int x) {tp = 0; Dfs2(x); int z = fa[x];int y = fa[x],now = Build(1,tp);if (x == rt) rt = now,fa[now] = 0;else {ch[y][ch[y][1] == x] = now; if (now) fa[now] = y;}while (z) maintain(z),z = fa[z]; }int LCA(int p,int q) {if (L[p] < L[q]) swap(p,q);for (int i = T - 1; i >= 0; i--)if (L[p] - (1<<i) >= L[q]) p = Fa[p][i];if (p == q) return p;for (int i = T - 1; i >= 0; i--)if (Fa[p][i] != Fa[q][i])p = Fa[p][i],q = Fa[q][i];return Fa[p][0]; } LL Dis(int x,int y) {return dis[x] + dis[y] - 2LL * dis[LCA(x,y)];}int getint() {char ch = getchar(); int ret = 0;while (ch < '0' || '9' < ch) ch = getchar();while ('0' <= ch && ch <= '9')ret = ret*10 + ch - '0',ch = getchar();return ret; }char s[20]; void Print(LL x) {int len = 0; while (x) s[++len] = x % 10LL,x /= 10LL;for (int i = len; i; i--) putchar(s[i] + '0'); puts(""); }int main() {#ifdef DMCfreopen("DMC.txt","r",stdin);freopen("test.txt","w",stdout);#endifn = getint(); m = getint();for (int i = 1; i < n; i++){int x = getint(),y,w;y = getint(); w = getint();v[x].push_back(E(y,w));v[y].push_back(E(x,w));}L[n / 2] = 1; Dfs(n / 2,0); dfn[n + 1] = -maxn; cnt = 2;Insert(rt,n + 1); dfn[n + 2] = maxn; Insert(rt,n + 2);while (m--){int x = getint(); bo[x] ^= 1;if (bo[x]){++cnt; a = 0; Insert(rt,x);if (cnt == 3) {puts("0"); continue;}if (a) Rebuild(a); int rk = Rank(rt,x);int A = rk > 2 ? Find(rt,rk - 1) : Find(rt,cnt - 1);int B = rk < cnt - 1 ? Find(rt,rk + 1) : Find(rt,2);Ans += (Dis(A,x) + Dis(B,x) - Dis(A,B)); Print(Ans);}else{if (cnt == 3){cnt = 2; Ans = 0; puts("0");Remove(rt,x); continue;}int rk = Rank(rt,x);int A = rk > 2 ? Find(rt,rk - 1) : Find(rt,cnt - 1);int B = rk < cnt - 1 ? Find(rt,rk + 1) : Find(rt,2);Ans += (Dis(A,B) - Dis(A,x) - Dis(B,x)); Print(Ans);a = 0; Remove(rt,x); if (a) Rebuild(a); --cnt;}}return 0; }總結
以上是生活随笔為你收集整理的3991: [SDOI2015]寻宝游戏的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux dbm数据库,Linux d
- 下一篇: Python爬虫介绍