bzoj2599 [IOI2011]Race(定权值最短树上路径)
来源:互联网 发布:采购数据报告体现 编辑:程序博客网 时间:2024/05/16 19:09
Description
给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 1000000
Input
第一行 两个整数 n, k
第二..n行 每行三个整数 表示一条无向边的两端和权值 (注意点的编号从0开始)
Output
一个整数 表示最小边数量 如果不存在这样的路径 输出-1
Sample Input
4 3
0 1 1
1 2 2
1 3 4
Sample Output
2
[Submit][Status][Discuss]
分析:
又是一道不单纯,很做作的题目
一开始我的想法很简单:增设一个数组,不光要记录路径的权值和,还要记录路径的长度
我们在统计路径条数的时候,直接维护一下长度min值就好了
这样当然是WA啦
因为点分治每次只能准确计算出过根结点的路径条数,
其他的不合法路径(包括不过根结点的路径,起点终点一样的路径,起点终点在一棵子树中的路径等等)都是需要去掉的
所以我们才必须要有去重的操作
这样一解释,
我就需要加一个数组num[i],表示长度为i且权值和为m的路径条数
最后输出的时候只要从小到大扫一遍就可以了
tip
在统计长度为k的路径条数时,cal数组的改写如下:
int cal(int now,int z){ tt=0; getdeep(now,0); sort(d+1,d+1+tt,cmp); int l=1,r=tt; while (l<r) { while (d[l].v+d[r].v>m&&r>l) r--; int rr=r; if (r<=l) break; while (d[l].v+d[r].v==m) { num[d[l].len+d[r].len]+=z; r--; if (r<=l) break; } r=rr; l++; }}
这样才可以不重不漏的高效率统计
//这里写代码片#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int N=200010;int f[N],sz[N],tt;int n,m,root,sum,tot=0,st[N],num[N];struct node{ int x,y,v,nxt;};node way[N<<1];bool vis[N];struct po{ int len,v; //在一个连通块内在到达根节点的路径权值和以及边数 };po line[N<<1],d[N];void add(int u,int w,int z){ tot++; way[tot].x=u;way[tot].y=w;way[tot].v=z;way[tot].nxt=st[u];st[u]=tot;}int cmp(const po &a,const po &b){ return a.v<b.v||a.v==b.v&&a.len<b.len;}void getroot(int now,int fa){ f[now]=0; sz[now]=1; for (int i=st[now];i;i=way[i].nxt) if (way[i].y!=fa&&!vis[way[i].y]) { getroot(way[i].y,now); sz[now]+=sz[way[i].y]; f[now]=max(f[now],sz[way[i].y]); } f[now]=max(f[now],sum-sz[now]); if (f[now]<f[root]) root=now;}void getdeep(int now,int fa){ d[++tt]=line[now]; for (int i=st[now];i;i=way[i].nxt) if (way[i].y!=fa&&!vis[way[i].y]) { line[way[i].y].v=line[now].v+way[i].v; line[way[i].y].len=line[now].len+1; getdeep(way[i].y,now); }}int cal(int now,int z){ tt=0; getdeep(now,0); sort(d+1,d+1+tt,cmp); int l=1,r=tt; while (l<r) { while (d[l].v+d[r].v>m&&r>l) r--; int rr=r; if (r<=l) break; while (d[l].v+d[r].v==m) { num[d[l].len+d[r].len]+=z; r--; if (r<=l) break; } r=rr; l++; }}void dfs(int now){ line[now].len=0; line[now].v=0; vis[now]=1; cal(now,1); for (int i=st[now];i;i=way[i].nxt) if (!vis[way[i].y]) { line[now].len=1; line[now].v=way[i].v; cal(way[i].y,-1); //一定要有去重操作 root=0; sum=sz[way[i].y]; getroot(way[i].y,root); dfs(root); }}int main(){ scanf("%d%d",&n,&m); for (int i=1;i<n;i++) { int u,w,z; scanf("%d%d%d",&u,&w,&z); u++; w++; add(u,w,z); add(w,u,z); } f[0]=1000000000; sum=n; root=0; getroot(1,0); dfs(root); for (int i=0;i<=n;i++) if (num[i]>0) { printf("%d",i); return 0; } printf("-1"); return 0;}
阅读全文
0 0
- bzoj2599 [IOI2011]Race(定权值最短树上路径)
- [BZOJ2599][IOI2011]Race-树上启发式合并(dsu on tree)
- [BZOJ2599][IOI2011]Race(点分治)
- [BZOJ2599][IOI2011]Race(点分治)
- 【bzoj2599】: [IOI2011]Race
- BZOJ2599: [IOI2011]Race
- bzoj2599【IOI2011】Race
- bzoj2599: [IOI2011]Race
- bzoj2599: [IOI2011]Race
- BZOJ2599: [IOI2011]Race
- 【IOI2011】bzoj2599 Race
- bzoj2599: [IOI2011]Race
- 【bzoj2599】[IOI2011]Race
- bzoj2599&COGS2648 [IOI2011]Race
- bzoj2599 [IOI2011]Race
- 【BZOJ2599】[IOI2011]Race
- 【bzoj2599】[IOI2011]Race 点分治
- 【BZOJ2599】[IOI2011]Race【点分治】
- linux关于bashrc与profile的区别(转)
- 自定义气泡背景
- 快速排序
- Shiro入门学习六
- hduoj 2007
- bzoj2599 [IOI2011]Race(定权值最短树上路径)
- 基于cubietruck的嵌入式系统移植
- linux下phpstudy如何使用
- 事务一致性 与异常抛出
- C语言中gets()和scanf()的区别
- “自顶向下,逐步求精”方法介绍
- 输入三个整数 用指针变量 从小到大排列
- iptables SNAT无效
- 聚合SDK开发思想