一開始還真沒想到。
發現從所有有寶藏的點出發繞一圈只要不刻意繞路答案都是一樣的,即我們呢要求的最後答案$ans = dis(x_1, x_2) + dis(x_2, x_3) +... + dis(x_, x_k) + dis(x_k, x_1)$。
不刻意繞遠路怎麼辦呢,我們把有寶藏的點按照$dfs$序,維護乙個有序的$set$就可以了。
每次插入就相當於找到乙個點$x$在$dfs$序中的前乙個點$lst$和後乙個點$nxt$,使最後的答案減去$dis(nxt, lst)$並加上$dis(x, nxt) + dis(lst, x)$,刪除同理。
我選擇用倍增來求$dis(x, y)$。
$set$的細節一開始沒想清楚,寫了一會兒。
時間複雜度$o(nlogn)$。
code:
#include #includeview code#include
using
namespace
std;
typedef
long
long
ll;const
int n = 1e5 + 5
;const
int lg = 20
;int n, qn, tot = 0
, head[n];
int dep[n], fa[n][lg], dfsc = 0
, id[n], mp[n];
ll ans =0ll, dis[n];
bool
ex[n];
sets;
struct
edge e[n
<< 1
];inline
void add(int
from, int
to, ll val)
template
inline
void read(t &x)
void dfs(int x, int fat, int
depth, ll nowdis)
}inline
void swap(int &x, int &y)
inline
int getlca(int x, int
y) inline ll getdis(
int x, int
y) int
main()
dfs(
1, 0, 1
, 0ll);
/*for(int i = 1; i <= n; i++)
printf("%d ", id[i]);
printf("\n");
*/for(int x, cnt = 0; qn--; )
set :: iterator it = s.find(id[x]), it2 =it;
if(it == s.begin()) it =s.end();
int lst = *(--it);
it =s.find(id[x]);
int nxt = 0
;
if((++it2) == s.end()) nxt = *(s.begin());
else nxt = *(++it);
ans += getdis(mp[lst], x) + getdis(mp[nxt], x) -getdis(mp[lst], mp[nxt]);
} else
set :: iterator it = s.find(id[x]), it2 =it;
if(it == s.begin()) it =s.end();
int lst = *(--it);
it =s.find(id[x]);
int nxt = 0
;
if((++it2) == s.end()) nxt = *(s.begin());
else nxt = *(++it);
ans -= getdis(mp[lst], x) + getdis(mp[nxt], x) -getdis(mp[lst], mp[nxt]);
s.erase(id[x]);
}printf(
"%lld\n
", ans);
}return0;
}
LG3320 SDOI2015 尋寶遊戲
洛谷 不需要建虛樹的虛樹2333。貪心地想一下,起始節點肯定是在關鍵點上,訪問順序就是 dfs 序。那麼對於每次詢問,ans dis s 1,s s sum dis s i,s 用 set 維護一下就好了 include include include include include include...
P3320 SDOI2015 尋寶遊戲
我們考慮現在已知點集,如何求最後的答案。發現答案就是求所有點構成的最小生成樹的邊權和減去最小生成樹直徑。嗯 這個東西我好像不會動態維護啊。哦,發現要回到最初轉移到的村莊,那不就是兩倍的最小生成樹的邊權嗎,題目變簡單了一點。現在就是考慮動態維護最小生成樹的邊權和,我們考慮將邊權下放。那麼當前這棵樹的答...
P3320 SDOI2015 尋寶遊戲 題解
題面 需要動態維護乙個點集的極小聯通子圖邊權和。可以發現,將點集 中的點按照 dfs 序從小到大排序之後,dist a 1,a 2 dist a 2,a 3 ldots dist a a k dist a k,a 1 恰好等於我們要維護的那個邊權和的兩倍。所以就開乙個set,在加入和刪除的時候加上或...