BZOJ 2599 Race 点的分治
来源:互联网 发布:4g网络架构 编辑:程序博客网 时间:2024/06/05 14:55
http://www.lydsy.com/JudgeOnline/problem.php?id=2599
题意:给一棵树,每条边有权.求一条路径,权值和等于K,且边的数量最小. (我会告诉你这就是题面?)
BZOJ的题就是好啊!一句话题意,赞一个。
这道题的思路还是点分治 ,类似于前面那篇文章里的两题,只不过转换成了求最小而不是计数,,,
每次找好重心u后,我们只考虑以u为根的子树,u的子树可以分治下去搞。
我们只考虑经过根的路径
由前面两题,可以很轻松的想到这样一个方法:
先搜出当前树所有的二元组(W,Dep),然后排序,扫描,但是注意,有可能两个点来自于同一棵子树,如果给二元组加一个信息属于哪颗子树,就变成了三元组。。。。判断两个元素是否满足条件需要满足三个信息,很是复杂啊。。不过我还是用这个方法写了老半天,最后实在搞不定就想其他方法了。
还是由以前做过的一些树形DP得到的启发,我们一棵一棵子树的去合并,也就是在当前子树找一个点(w,dep),在前面的子树找一个点,这个点
到根的权值和是 K-W ,并且深度最小,我们就记为dp[K-w]好了,(这种方法在合并子树的问题上还是蛮常用的),然后我们每次先询问再更新DP数组就好了,要注意DP数组的初始化,不能全部都清空,要不果断TLE。。。。
这题的数据应该还是蛮好造的吧。。。。
附上代码:速度略慢啊,跑了17s多
#include<cstdio>#include<cstring>#include<vector>#include<algorithm>using namespace std;const int maxn = 222222;struct Divided_Conquer { struct Edge{ int v , w; Edge(){} Edge(int v,int w): v(v),w(w) { } }; bool Del[maxn]; vector<Edge> E[maxn]; int N , K; int size[maxn] , opt[maxn] ,dp[1000010]; vector<int> tnode ;vector<pair<int,int> > now; void Dfs(int u,int f) { tnode.push_back(u); size[u] = 1; opt[u] = 0; for(vector<Edge>::iterator it = E[u].begin(); it != E[u].end(); it++) { if(!Del[it->v] && it->v != f) { Dfs(it->v,u); size[u] += size[it->v]; opt[u] = max(opt[u],size[it->v]); } } } int Get_Root(int u) { tnode.clear(); Dfs(u,-1); int mi = maxn , ans = -1; for(vector<int>::iterator it = tnode.begin(); it != tnode.end(); it++) { opt[*it] = max(opt[*it],size[u]-size[*it]) ; if(opt[*it] < mi) { mi = opt[*it]; ans = *it; } } return ans; } vector<int> all ; void Get_Dis(int u,int len,int dep,int fa) {now.push_back(make_pair(len,dep)); for(vector<Edge>::iterator it = E[u].begin(); it != E[u].end(); it++) { if(!Del[it->v] && it->v != fa) { Get_Dis(it->v,len+it->w,dep+1,u); } } }inline void Merge(vector<pair<int,int> > a){for(vector<pair<int,int> >::iterator it = a.begin(); it != a.end(); it++) {if(it->first<=K) {all.push_back(it->first);Update(dp[it->first],it->second);}}} void Solve(int u) { u = Get_Root(u); all.clear(); int nch = 0;dp[0] = 0; for(vector<Edge>::iterator it = E[u].begin(); it != E[u].end(); it++) { if(!Del[it->v]){nch ++;now.clear();Get_Dis(it->v,it->w,1,u);Calc(now);Merge(now);} }for(vector<int>::iterator it = all.begin(); it != all.end(); it++) {dp[*it] = -1;} Del[u] = true; for(vector<Edge>::iterator it = E[u].begin(); it != E[u].end(); it++) { if(!Del[it->v]) { Solve(it->v); } } } inline void Calc(vector<pair<int,int> >now){for(vector<pair<int,int> >::iterator it = now.begin(); it != now.end(); it++) {if(it->first <= K ) {if(dp[K-it->first] != -1) {Update(Ans,dp[K-it->first]+it->second);}}} } inline void Update(int &x,int cmp) { if(x==-1 || x > cmp) x = cmp; } void Init(){ int a,b,c; Ans = -1; scanf("%d%d",&N,&K);fill(dp,dp+K+1,-1); for(int i = 1; i < N; i++) { scanf("%d%d%d",&a,&b,&c); a++ ; b++; E[a].push_back(Edge(b,c)); E[b].push_back(Edge(a,c)); } } int Ans;}sol;int main(){ sol.Init(); sol.Solve(1); printf("%d\n",sol.Ans); return 0;}
- BZOJ 2599 Race 点的分治
- BZOJ 2599 IOI2011 Race 树的点分治
- 【BZOJ 2599】 [IOI2011]Race 树的点分治
- bzoj 2599: [IOI2011]Race(树的点分治)
- BZOJ 2599 [IOI2011]Race【Tree,点分治】
- 【点分治】BZOJ 2599:[IOI2011]Race
- BZOJ 2599 IOI 2011 Race 点分治
- bzoj 2599: [IOI2011]Race (点分治)
- Bzoj 2599: [IOI2011]Race(点分治)
- 点分治[BZOJ]2599: [IOI2011]Race
- 【BZOJ】2599 [IOI2011]Race 点分治
- BZOJ 2599: [IOI2011]Race 点分治题解
- bzoj 2599: [IOI2011]Race 点分治
- bzoj 2599 Race树的分治
- 2599: [IOI2011]Race|树的点分治
- 【BZOJ】【P2599】【IOI2011】【Race】【题解】【点分治】
- 2599: [IOI2011]Race 点分治
- BZOJ 2599 IOI 2011 Race 树的分治
- 10397 - Connect the Campus
- virtualbox 虚拟ubuntu如何全屏显示
- 实习第一周
- 调用c的printf
- 分割字符串 sscanf的用法
- BZOJ 2599 Race 点的分治
- HDOJ 1069
- 将JAVA 项目打包成JAR 并运行
- wp8小钟表
- 【const】用法详解
- Node.js与Restful API
- HTTP POST GET 本质区别详解
- UDP 网络广播通讯
- HDOJ 2512