首页 > 代码库 > 【BZOJ2599】[IOI2011]Race 树的点分治
【BZOJ2599】[IOI2011]Race 树的点分治
【BZOJ2599】[IOI2011]Race
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
0 1 1
1 2 2
1 3 4
Sample Output
2
题解:本题大部分代码都与POJ1741那道模板题相同,只不过是calc函数里有些不一样
如果我们想计算一棵子树里的答案,仍然是先按照每个点到根的距离排序,然后用双指针法算出长度=m的路径,那么问题来了,我们怎样将答案中的非简单路径去掉呢?
由于我们最终要求的是经过边最少的长度=m的简单路径,那么我们可以用ans[i]保存经过i条边的路径数,然后在calc的时候直接修改ans就行了
#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;const int maxn=200010;int to[maxn<<1],next[maxn<<1],val[maxn<<1],dep[maxn],s[maxn],head[maxn],siz[maxn];int vis[maxn],ans[maxn],p[maxn];int n,m,tot,cnt,root,maxx;bool cmp(int a,int b){ return s[a]<s[b];}void add(int a,int b,int c){ to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;}void getroot(int x,int fa){ int i,mx=0; siz[x]=1; for(i=head[x];i!=-1;i=next[i]) { if(to[i]==fa||vis[to[i]]) continue; getroot(to[i],x); siz[x]+=siz[to[i]]; mx=max(mx,siz[to[i]]); } mx=max(mx,tot-siz[x]); if(maxx>mx) root=x,maxx=mx;}void getdep(int x,int fa){ p[++p[0]]=x; for(int i=head[x];i!=-1;i=next[i]) { if(to[i]==fa||vis[to[i]]) continue; s[to[i]]=s[x]+val[i],dep[to[i]]=dep[x]+1; getdep(to[i],x); }}void calc(int x,int flag){ p[0]=0,getdep(x,0); sort(p+1,p+p[0]+1,cmp); int l=1,r=p[0],i; for(;l<r;l++) { while(l<r&&s[p[l]]+s[p[r]]>m) r--; for(i=r;i>l&&s[p[l]]+s[p[i]]==m;i--) ans[dep[p[l]]+dep[p[i]]]+=flag; }}void dfs(int x){ vis[x]=1; s[x]=dep[x]=0,calc(x,1); for(int i=head[x];i!=-1;i=next[i]) { if(vis[to[i]]) continue; s[to[i]]=val[i],dep[to[i]]=1,calc(to[i],-1); maxx=1<<30,tot=siz[to[i]],getroot(to[i],x); dfs(root); }}int main(){ scanf("%d%d",&n,&m); int i,a,b,c; memset(head,-1,sizeof(head)); for(i=1;i<n;i++) { scanf("%d%d%d",&a,&b,&c),a++,b++; add(a,b,c),add(b,a,c); } maxx=1<<30; getroot(1,0); dfs(1); for(i=1;i<=n;i++) { if(ans[i]) { printf("%d\n",i); return 0; } } printf("-1"); return 0;}
【BZOJ2599】[IOI2011]Race 树的点分治
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。