您的位置:首页 > 其它

[BZOJ3991]SDOI2015寻宝游戏|set|虚树

2015-06-20 21:43 447 查看
  询问就是求包含所有宝藏点的最小子图(貌似叫虚树?

  按dfs序用set维护宝藏点的序列,并把set中相邻点(头和尾也算相邻)在树中路径的距离累加记为sum,删除序列中第i个点时,设前面为l[i](l[1]=n),后面为ri,把l[i]到i和到r[i]的距离在sum中减去,并加上l[i]到r[i]的距离,插入是也是类似的。。

#include<cstdio>
#include<iostream>
#include<set>
#define ll long long
#define N 100005
#define inf 0x3fffffff
using namespace std;
struct edge{
int e,q,next;
}ed[N*2];
int n,m,ne=0,s,e,q,i,j,l,r,tim,t,a
,fa
[18],dfn
,u
,nd
,D
;
ll ans,tmp,d
;
set<int> st;
void add(int s,int e,int q)
{
ed[++ne].e=e;ed[ne].q=q;
ed[ne].next=a[s];a[s]=ne;
}
void dfs(int x)
{
for (int j=1;j<18;j++) fa[x][j]=fa[fa[x][j-1]][j-1];
dfn[x]=++tim;nd[tim]=x;
for (int j=a[x];j;j=ed[j].next)
if (ed[j].e!=fa[x][0])
{
d[ed[j].e]=d[x]+(ll)ed[j].q;fa[ed[j].e][0]=x;
D[ed[j].e]=D[x]+1;
dfs(ed[j].e);
}
}
int lca(int a,int b)
{
if (D[a]>D[b]) swap(a,b);
for (int j=17;j>=0;j--)
if (fa[b][j]&&D[fa[b][j]]>=D[a]) b=fa[b][j];
if (a==b) return a;
for (int j=17;j>=0;j--)
if (fa[a][j]!=fa[b][j]) a=fa[a][j],b=fa[b][j];
return fa[a][0];
}
ll dis(int a,int b)
{
int f=lca(a,b);
return d[a]+d[b]-2*d[f];
}
int main()
{
freopen("3991.in","r",stdin);
scanf("%d%d",&n,&m);
for (i=1;i<=n;i++) a[i]=u[i]=0;
for (i=1;i<n;i++)
{
scanf("%d%d%d",&s,&e,&q);
add(s,e,q);add(e,s,q);
}
fa[1][0]=d[1]=D[1]=0;tim=0;
dfs(1);ans=0;
st.insert(inf);st.insert(-inf);
for (i=1;i<=m;i++)
{
scanf("%d",&e);
if (u[e]) st.erase(dfn[e]),t=-1;else st.insert(dfn[e]),t=1;
u[e]^=1;
l=*--st.lower_bound(dfn[e]);r=*st.upper_bound(dfn[e]);
if (l!=-inf) ans+=(ll)t*dis(nd[l],e);
if (r!=inf) ans+=(ll)t*dis(nd[r],e);
if (l!=-inf&&r!=inf) ans-=(ll)t*dis(nd[l],nd[r]);
if (st.size()>3) tmp=dis(nd[*st.upper_bound(-inf)],nd[*--st.lower_bound(inf)]);else tmp=0;
printf("%lld\n",ans+tmp);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: