3991: [SDOI2015]尋寶遊戲
Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 1379 Solved: 671
[Submit][Status][Discuss]
Description
小B最近正在玩一個尋寶遊戲,這個遊戲的地圖中有N個村莊和N-1條道路,並且任何兩個村莊之間有且僅有一條路徑可達。遊戲開始時,玩家可以任意選擇一個村莊,瞬間轉移到這個村莊,然後可以任意在地圖的道路上行走,若走到某個村莊中有寶物,則視爲找到該村莊內的寶物,直到找到所有寶物並返回到最初轉移到的村莊爲止。小B希望評測一下這個遊戲的難度,因此他需要知道玩家找到所有寶物需要行走的最短路程。但是這個遊戲中寶物經常變化,有時某個村莊中會突然出現寶物,有時某個村莊內的寶物會突然消失,因此小B需要不斷地更新數據,但是小B太懶了,不願意自己計算,因此他向你求助。爲了簡化問題,我們認爲最開始時所有村莊內均沒有寶物
Input
第一行,兩個整數N、M,其中M爲寶物的變動次數。
Output
M行,每行一個整數,其中第i行的整數表示第i次操作之後玩家找到所有寶物需要行走的最短路程。若只有一個村莊內有寶物,或者所有村莊內都沒有寶物,則輸出0。
Sample Input
1 2 30
2 3 50
2 4 60
2
3
4
2
1
Sample Output
100
220
220
280
HINT
1<=N<=100000
Source
數據太水了
數據太水了
#include<iostream>
#include<cstring>
#include<cstdio>
#include<set>
using namespace std;
const int N = 100000 + 5;
typedef long long ll;
int cnt,n,m,sz,opt; bool vis[N];
int last[N],dep[N],anc[N][20],in[N],inv_in[N],siz[N];
ll d[N],ans;
struct Edge{ int to, next, v; }e[N<<1];
void insert( int u, int v, int w ){
e[++cnt].to = v; e[cnt].next = last[u]; e[cnt].v = w; last[u] = cnt;
e[++cnt].to = u; e[cnt].next = last[v]; e[cnt].v = w; last[v] = cnt;
}
void dfs( int x, int f ){
siz[x] = 1; in[x] = ++sz; inv_in[sz] = x;
for( int p = 1; p <= 16; p++ ) anc[x][p] = anc[anc[x][p-1]][p-1];
for( int i = last[x]; i; i = e[i].next )
if( e[i].to ^ f ){
dep[e[i].to] = dep[x]+1;
d[e[i].to] = d[x] + e[i].v;
anc[e[i].to][0] = x;
dfs( e[i].to, x );
siz[x] += siz[e[i].to];
}
}
int lca( int x, int y ){
if( dep[x] < dep[y] ) swap(x,y);
int t = dep[x] - dep[y];
for( int p = 0; p <= 16; p++ )
if( (1<<p)&t )
x = anc[x][p];
if( x == y ) return x;
for( int p = 16; p >= 0; p-- )
if( anc[x][p] != anc[y][p] )
x = anc[x][p], y = anc[y][p];
return anc[x][0];
}
ll dis( int x, int y ){
return d[x] + d[y] - 2*d[lca( x, y )];
}
set <int> q;
set <int> :: iterator it;
int next( int x ){
it = q.find(in[x]);
return ++it == q.end() ? 0 : inv_in[*it];
}
int pre( int x ){
it = q.find(in[x]);
return it == q.begin() ? 0 : inv_in[*--it];
}
void set_erase( int x ){
int pr = pre(x), ne = next(x);
q.erase(in[x]);
if( pr ) ans -= dis( pr, x );
if( ne ) ans -= dis( x, ne );
if( pr && ne ) ans += dis( pr, ne );
}
void set_insert( int x ){
q.insert(in[x]);
int pr = pre(x), ne = next(x);
if( pr ) ans += dis( pr, x );
if( ne ) ans += dis( x, ne );
if( pr && ne ) ans -= dis( pr, ne );
}
int main(){
scanf( "%d%d", &n, &m );
for( int i = 1,u,v,w; i < n; i++ ){
scanf( "%d%d%d", &u, &v, &w );
insert( u, v, w );
}
dfs( 1, 0 );
while( m-- ){
int x;
scanf( "%d", &x );
if( vis[x] ) set_erase(x), vis[x] = 0;
else set_insert(x), vis[x] = 1;
if( !q.size() ) puts("0");
else printf( "%lld\n", ans + dis( inv_in[*q.begin()], inv_in[*--q.end()] ) );
}
return 0;
}