bzoj3991 寻宝游戏 dfs&set

来源:互联网 发布:2015年中国进出口数据 编辑:程序博客网 时间:2024/04/29 14:06

       考虑关键点(有宝藏的点)及其lca构成的虚树,由于最后还需要回到原点,因此答案相当于虚树中所有边权的和的两倍。

       考虑树的边权的两倍怎么求,实际上就是按dfs序排序之后第一个点和第二个点,第二个点和第三个点……最后一个点和第一个点的距离的和。那么用set维护dfs序,插入和删除的时候统计一下就好了。

AC代码如下:

#include<iostream>#include<cstdio>#include<cstring>#include<set>#define N 100005#define inf 1000000000#define ll long longusing namespace std;set<int> s;int n,m,tot,dfsclk,dep[N],fst[N],pnt[N<<1],nxt[N<<1],pos[N],id[N],fa[N][17],a[N],bin[25];ll d[N],len[N<<1];int read(){int x=0; char ch=getchar();while (ch<'0' || ch>'9') ch=getchar();while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }return x;}void add(int x,int y,ll z){pnt[++tot]=y; len[tot]=z; nxt[tot]=fst[x]; fst[x]=tot;}void dfs(int x){pos[x]=++dfsclk; id[dfsclk]=x; int p,i;for (i=1; bin[i]<=dep[x]; i++) fa[x][i]=fa[fa[x][i-1]][i-1];for (p=fst[x]; p; p=nxt[p]){int y=pnt[p];if (y!=fa[x][0]){fa[y][0]=x; d[y]=d[x]+len[p];dep[y]=dep[x]+1; dfs(y);}}}int lca(int x,int y){if (dep[x]<dep[y]) swap(x,y); int tmp=dep[x]-dep[y],i;for (i=0; bin[i]<=tmp; i++)if (tmp&bin[i]) x=fa[x][i];for (i=16; i>=0; i--)if (fa[x][i]!=fa[y][i]){ x=fa[x][i]; y=fa[y][i]; }return (x==y)?x:fa[x][0];}ll dist(int x,int y){ return d[x]+d[y]-(d[lca(x,y)]<<1); }int main(){n=read(); m=read(); int i;bin[0]=1; for (i=1; i<=17; i++) bin[i]=bin[i-1]<<1;for (i=1; i<n; i++){int x=read(),y=read(),z=read();add(x,y,(ll)z); add(y,x,(ll)z);}dfs(1); ll ans=0,tmp;s.insert(-inf); s.insert(inf); set<int>::iterator it;for (i=1; i<=m; i++){int k=read(),t;if (a[k]){ s.erase(pos[k]); t=-1; }else{ s.insert(pos[k]); t=1; }a[k]^=1; it=s.upper_bound(pos[k]);int r=*it,l=*(--it); if (l>=pos[k]) l=*(--it);if (l!=-inf) ans+=dist(id[l],k)*t; if (r!=inf) ans+=dist(id[r],k)*t;if (l!=-inf && r!=inf) ans-=dist(id[l],id[r])*t;tmp=(s.size()>3)?dist(id[*s.upper_bound(-inf)],id[*--s.lower_bound(inf)]):0;printf("%lld\n",ans+tmp);}return 0;}


by lych

2016.3.6

0 0
原创粉丝点击