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返回第一个大于当前值的位置,可以事先加好正无穷和负无穷)
假如没有修改操作的话,就像一个简单的树形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; }
相关文章推荐
- 【dfs序】【set】bzoj3991 [Sdoi2015]寻宝游戏
- BZOJ3991 [SDOI2015]寻宝游戏
- BZOJ 3991: [SDOI2015]寻宝游戏
- BZOJ3991 [SDOI2015]寻宝游戏 【dfs序 + lca + STL】
- BZOJ 3991 SDOI 2015 寻宝游戏(异象石) LCA + Set + DFS序
- [BZOJ3991]SDOI2015寻宝游戏|set|虚树
- bzoj 3991: [SDOI2015]寻宝游戏 (set+LCA+dfs序+虚树)
- 【BZOJ】【3991】【SDOI2015】寻宝游戏
- 树形结构的维护:BZOJ 3991: [SDOI2015]寻宝游戏
- 【BZOJ 3991】[SDOI2015]寻宝游戏 虚树
- 【bzoj3991】【SDOI2015】【寻宝游戏】【dfs序】
- bzoj 3991: [SDOI2015]寻宝游戏 dfs序+虚树+set
- BZOJ 3991 [SDOI2015]寻宝游戏
- bzoj3991 [SDOI2015]寻宝游戏
- 【BZOJ3991】【SDOI2015】寻宝游戏
- 【SDOI2015】bzoj3991 寻宝游戏
- BZOJ3991: [SDOI2015]寻宝游戏
- [BZOJ3991][SDOI2015]寻宝游戏(dfs序+set/平衡树)
- BZOJ 3991: [SDOI2015]寻宝游戏 [虚树 树链的并 set]
- bzoj3991 [SDOI2015]寻宝游戏