[2015hdu多校联赛补题]hdu5296 Annoying problem
2015-08-02 21:55
337 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5296
题意:给你一棵n个结点的边权树和一个树上点的集合,开始时集合为空
然后进行两种操作:
1、如果结点u不在集合中,那么将u加入集合
2、如果结点u在集合中,那么删除u
每次操作后输出包含点集合的最小联通子图的边权和
题解:
其实问题的本质就是求结点u与子图的距离(如果在子图内部距离为0),yy一下可以想到,若x、y为集合中与u最近的两点,那么dis(u,子图)=dis(u,联通u、x、y三点的汇点)
问题转化为求x、y,将树上结点以dfs序重标号,如果u在点集标号集的外侧,那么x、y分别为点集标号集的最大标号与最小标号,如果在内侧,那么x、y分别为u的左右
然后求u与 联通u、x、y三点汇点 的距离:
dis(u,联通u、x、y三点的汇点)=(dis(u,x)+dis(u,y)+dis(x,y))/2-dis(x,y)
dis(a,b)=dfn[a] +dfn[b] -2dfn[lca(a,b)] (lca和dfn都是求树链长度用到的东西,lca(a,b):a、b的最近公共祖先,dfn[x]:根结点到x的路径的边权和)
hdu 5296
题意:给你一棵n个结点的边权树和一个树上点的集合,开始时集合为空
然后进行两种操作:
1、如果结点u不在集合中,那么将u加入集合
2、如果结点u在集合中,那么删除u
每次操作后输出包含点集合的最小联通子图的边权和
题解:
其实问题的本质就是求结点u与子图的距离(如果在子图内部距离为0),yy一下可以想到,若x、y为集合中与u最近的两点,那么dis(u,子图)=dis(u,联通u、x、y三点的汇点)
问题转化为求x、y,将树上结点以dfs序重标号,如果u在点集标号集的外侧,那么x、y分别为点集标号集的最大标号与最小标号,如果在内侧,那么x、y分别为u的左右
然后求u与 联通u、x、y三点汇点 的距离:
dis(u,联通u、x、y三点的汇点)=(dis(u,x)+dis(u,y)+dis(x,y))/2-dis(x,y)
dis(a,b)=dfn[a] +dfn[b] -2dfn[lca(a,b)] (lca和dfn都是求树链长度用到的东西,lca(a,b):a、b的最近公共祖先,dfn[x]:根结点到x的路径的边权和)
/* * Problem: * Author: SHJWUDP * Created Time: 2015/8/2 星期日 15:20:01 * File Name: 233.cpp * State: * Memo: */ #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <set> using namespace std; struct Edge { int u, v, w; Edge(int u, int v, int w):u(u), v(v), w(w){} }; int n, q; vector<Edge> edges; vector<vector<int> > G; vector<int> pos, id, dep, dfn; vector<vector<int> > fa; set<int> S; int root, cnt; void init(int sz) { edges.clear(); G.assign(sz, vector<int>(0)); S.clear(); pos.resize(sz); id.resize(sz); dep.resize(sz); dfn.resize(sz); fa.assign(sz, vector<int>(20)); } void addEdge(int u, int v, int w) { edges.push_back(Edge(u, v, w)); G[u].push_back(edges.size()-1); } void dfs(int u) { pos[u]=++cnt; id[cnt]=u; for(int k=1; k<20; k++) { fa[u][k]=fa[fa[u][k-1]][k-1]; } for(int i : G[u]) { Edge & e=edges[i]; if(e.v==fa[u][0]) continue; dfn[e.v]=dfn[u]+e.w; dep[e.v]=dep[u]+1; fa[e.v][0]=u; dfs(e.v); } } int lca(int u, int v) { if(dep[u]<dep[v]) swap(u, v); for(int k=19; k>=0; k--) { if(dep[fa[u][k]]>=dep[v]) { u=fa[u][k]; } } if(u==v) return u; for(int k=19; k>=0; k--) { if(fa[u][k]!=fa[v][k]) { u=fa[u][k]; v=fa[v][k]; } } return fa[u][0]; } int func(int u) { int res=0; if(!S.empty()) { auto it=S.lower_bound(pos[u]); int x, y; if(it==S.begin() || it==S.end()) { x=id[*S.begin()]; y=id[*S.rbegin()]; } else { x=id[*it]; y=id[*--it]; } res=dfn[u]-dfn[lca(u, x)]-dfn[lca(u, y)]+dfn[lca(x, y)]; } return res; } int main() { #ifndef ONLINE_JUDGE freopen("in", "r", stdin); //freopen("out", "w", stdout); #endif int T, now=0; scanf("%d", &T); while(T--) { scanf("%d%d", &n, &q); init(n+1); for(int i=0; i<n-1; i++) { int a, b, c; scanf("%d%d%d", &a, &b, &c); addEdge(a, b, c); addEdge(b, a, c); } root=1; cnt=0; fa[root][0]=root; dep[root]=0; dfn[root]=0; dfs(root); printf("Case #%d:\n", ++now); int ans=0; while(q--) { int op, u; scanf("%d%d", &op, &u); auto it=S.find(pos[u]); if(op==1 && it==S.end()) { ans+=func(u); S.insert(pos[u]); } else if(op==2 && it!=S.end()) { S.erase(it); ans-=func(u); } printf("%d\n", ans); } } return 0; }
hdu 5296
相关文章推荐
- 【effective c++读书笔记】【第4章】设计与声明(1)
- poj 3436 网络流构图经典
- STM32串口程序(寄存器版)
- PageRank与R语言实现
- linux进程间的通信--共享内存
- Qt 判断一个IP地址是否有效
- HDU1018(也是水题)
- tomcat下配置https环境(windows环境)
- IOS之pageControl
- 移植u-boot-2015.07-rc3之修改代码支持SDRAM和SPL启动(二)
- Android基础知识之四大组件Activity(四)保存Activity的状态
- POJ 3087 Shuffle'm Up
- Photoshop 意境文字效果图片制作
- UVa 11987 并查集 Almost Union-Find
- 使用wamp集成开发环境,dos命令下数据库乱码解决问题
- 用Maven打印出配置变量
- ubuntu-12.04.5-desktop-i386.iso:ubuntu-12.04.5-desktop-i386:安装Oracle11gR2
- scala的REPL shell的调用
- java命令行提示:找不到或无法加载主类
- 剑指offer面试题java实现之题4:替换空格