1. 程式人生 > >【BZOJ3991】尋寶遊戲(動態規劃)

【BZOJ3991】尋寶遊戲(動態規劃)

維護 inline printf insert struct print clu getch map

【BZOJ3991】尋寶遊戲(動態規劃)

題面

BZOJ

題解

很明顯,從任意一個有寶藏的點開始,每次走到相鄰的\(dfs\)的節點就行了。
證明?
類似把一棵樹上的關鍵點全部標記出來
顯然是要走一個大環。
這樣沿著\(dfs\)序從左至右依次便利是最優的。
用一個\(set\)維護一下就行了

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map> #include<vector> #include<queue> using namespace std; #define ll long long #define RG register #define MAX 111111 inline int read() { RG int x=0,t=1;RG char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if
(ch=='-')t=-1,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return x*t; } int n,m; struct Line{int v,next;ll w;}e[MAX<<1]; int h[MAX],cnt=1; inline void Add(int u,int v,ll w){e[cnt]=(Line){v,h[u],w};h[u]=cnt++;} int dfn[MAX],low[MAX],size[MAX],hson[MAX],top[MAX],dep[MAX],fa[MAX],tim; ll dis[MAX]; void
dfs1(int u,int ff) { size[u]=1;fa[u]=ff;dep[u]=dep[ff]+1; for(int i=h[u];i;i=e[i].next) { int v=e[i].v;if(v==ff)continue; dis[v]=dis[u]+e[i].w; dfs1(v,u);size[u]+=size[v]; if(size[v]>size[hson[u]])hson[u]=v; dis[v]=dis[u]+e[i].w; } } void dfs2(int u,int tp) { top[u]=tp;dfn[u]=++tim;low[tim]=u; if(hson[u])dfs2(hson[u],tp); for(int i=h[u];i;i=e[i].next) { int v=e[i].v; if(v==fa[u]||v==hson[u])continue; dfs2(v,v); } } int LCA(int u,int v) { while(top[u]^top[v])dep[top[u]]<dep[top[v]]?v=fa[top[v]]:u=fa[top[u]]; return dep[u]<dep[v]?u:v; } ll Dis(int u,int v){return dis[u]+dis[v]-2*dis[LCA(u,v)];} bool imp[MAX]; set<int> P; ll ans=0; int main() { n=read();m=read(); for(int i=1;i<n;++i) { int u=read(),v=read(),w=read(); Add(u,v,w);Add(v,u,w); } dfs1(1,0);dfs2(1,1); set<int>::iterator it,it1,it2; while(m--) { int x=read(); if(!imp[x]) { P.insert(dfn[x]); it=it1=it2=P.find(dfn[x]);--it1;++it2; if(it!=P.begin())ans+=Dis(x,low[*it1]); if(it2!=P.end())ans+=Dis(x,low[*it2]); if(it!=P.begin()&&it2!=P.end())ans-=Dis(low[*it1],low[*it2]); } else { it=it1=it2=P.find(dfn[x]);--it1;++it2; if(it!=P.begin())ans-=Dis(x,low[*it1]); if(it2!=P.end())ans-=Dis(x,low[*it2]); if(it!=P.begin()&&it2!=P.end())ans+=Dis(low[*it1],low[*it2]); P.erase(dfn[x]); } imp[x]^=1; if(P.size()<=1){puts("0");continue;} it=P.end();--it; printf("%lld\n",ans+Dis(low[*P.begin()],low[*it])); } return 0; }

【BZOJ3991】尋寶遊戲(動態規劃)