您的位置:首页 > 其它

BZOJ 3991: [SDOI2015]寻宝游戏

2015-04-25 14:18 375 查看
题目大意:给定一棵树,其中有若干个关键点,任意选择起点,求从起点出发访问所有关键点又回到起点的最小边权总和,有M个修改操作,每次修改一个关键点。

假如没有修改操作的话,就像一个简单的树形DP,方程如下:

f[i]=sigma{f[son]}+sigma{e.v*2}.观察一下DP的过程,就是不断地从前面的点走到后面的点,所以我们可以不用这么麻烦,直接按关键点的dfs序排序走一遍就可以了。修改的时候只是加入或删除其中的一个点,所以找到这个点的前驱和后继,计算一下对答案的影响就好了,最后注意要回起点。

Tips:计算前驱和后继可以用C++stl里的set,不得不说set真是神器啊!(lower_bound返回第一个大于等于当前值的位置,upper_bound返回第一个大于当前值的位置,可以事先加好正无穷和负无穷)

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#include<set>
using namespace std;
const int maxn=100000+10;
const int INF=1000000000;
set<int> hm;
int n,m,dfn[maxn],fa[maxn][20],flag[maxn],pre[maxn],dep[maxn],dfs_clock;
long long dis[maxn],ans;
struct node
{
int to,cost;
};
vector<node> g[maxn];
void dfs(int p)
{
pre[p]=++dfs_clock;dfn[dfs_clock]=p;
for(int i=1;i<=19;i++)
if((1<<i)<=dep[p]) fa[p][i]=fa[fa[p][i-1]][i-1];
else break;
for(int i=0;i<g[p].size();i++)
{
node e=g[p][i];int v=e.to;
if(v==fa[p][0]) continue;
fa[v][0]=p;dep[v]=dep[p]+1;dis[v]=dis[p]+e.cost;dfs(v);
}
}
int lca(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
int t=dep[x]-dep[y];
for(int i=0;i<20;i++)
if((1<<i)&t)
x=fa[x][i];
for(int i=19;i>=0;i--)
if(fa[x][i]!=fa[y][i])
{
x=fa[x][i];
y=fa[y][i];
}
if(x==y) return x;
else return fa[x][0];
}
long long calc(int x,int y)
{
int f=lca(x,y);
long long res=dis[x]+dis[y]-(long long)2*dis[f];
return res;
}
int main()
{
//freopen("3991.in","r",stdin);
//freopen("3991.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
g[x].push_back((node){y,z});
g[y].push_back((node){x,z});
}
hm.insert(-INF);hm.insert(INF);
dfs(1);
for(int i=1;i<=m;i++)
{
int x;scanf("%d",&x);
flag[x]^=1;long long tt=0;
if(flag[x])
{
int l=*--hm.lower_bound(pre[x]),r=*hm.upper_bound(pre[x]);
if(l!=-INF) ans+=calc(dfn[l],x);
if(r!=INF) ans+=calc(x,dfn[r]);
if(l!=-INF&&r!=INF) ans-=calc(dfn[l],dfn[r]);
hm.insert(pre[x]);
}
else
{
hm.erase(pre[x]);
int l=*--hm.lower_bound(pre[x]),r=*hm.upper_bound(pre[x]);
if(l!=-INF) ans-=calc(dfn[l],x);
if(r!=INF) ans-=calc(x,dfn[r]);
if(l!=-INF&&r!=INF) ans+=calc(dfn[l],dfn[r]);
}
if(hm.size()>=3)
{
int l=*++hm.lower_bound(-INF);
int r=*--hm.lower_bound(INF);
tt=calc(dfn[l],dfn[r]);
}
printf("%lld\n",ans+tt);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: