Luogu 3320 SDOI2015 尋寶遊戲

2022-06-13 04:09:12 字數 2175 閱讀 8835

一開始還真沒想到。

發現從所有有寶藏的點出發繞一圈只要不刻意繞路答案都是一樣的,即我們呢要求的最後答案$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 #include 

#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;

}

view code

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,在加入和刪除的時候加上或...