[BZOJ1912][Apio2010]patrol 巡逻(dfs+并查集+树形dp)
2016-05-03 14:53
330 查看
题目描述
传送门题解
k=1时,首先使所有的路权都为1,求树上最长链,答案为2×(n-1)-(len1-1)k=2时,在k=1的基础上,将第一次选取的链上的边权都赋为-1,然后再求树的直径记为len2,答案为2×(n-1)-(len1-1)-(len2-1)
注意第二次求树的直径有负边权dfs就不管用了,用树形dp
代码
#include<iostream> #include<cstring> #include<cstdio> using namespace std; const int max_n=1e5+5; const int max_m=max_n; const int max_e=max_m*2; const int INF=2e9; int n,k,maxn,root,oldroot,len1,len2; int tot,point[max_n],next[max_e],v[max_e],c[max_e]; int father[max_n],h[max_n],f[max_n],F[max_n],G[max_n]; struct hp{int x,y;}edge[max_m]; inline void add(int x,int y){ ++tot; next[tot]=point[x]; point[x]=tot; v[tot]=y; ++tot; next[tot]=point[y]; point[y]=tot; v[tot]=x; } inline void addedge(int x,int y,int z){ ++tot; next[tot]=point[x]; point[x]=tot; v[tot]=y; c[tot]=z; ++tot; next[tot]=point[y]; point[y]=tot; v[tot]=x; c[tot]=z; } inline void dfs(int x,int fa,int dep){ father[x]=fa; h[x]=dep; if (h[x]>maxn){maxn=h[x];root=x;} for (int i=point[x];i;i=next[i]) if (v[i]!=fa) dfs(v[i],x,dep+1); } inline int find(int x){if (x==f[x]) return x; else return f[x]=find(f[x]);} inline void merge(int x,int y){int f1=find(x),f2=find(y); f[f1]=f2;} inline void treedp(int x,int fa){ for (int i=point[x];i;i=next[i]) if (v[i]!=fa){ treedp(v[i],x); if (F[v[i]]+c[i]>F[x]){ G[x]=F[x]; F[x]=F[v[i]]+c[i]; } else G[x]=max(G[x],F[v[i]]+c[i]); } len2=max(len2,F[x]+G[x]); } int main(){ scanf("%d%d",&n,&k); for (int i=1;i<n;++i){ scanf("%d%d",&edge[i].x,&edge[i].y); add(edge[i].x,edge[i].y); } maxn=0; dfs(1,0,0); oldroot=root; memset(h,0,sizeof(0)),maxn=0; dfs(root,0,0); if (k==1){ printf("%d\n",maxn+1+(n-1-maxn)*2); return 0; } len1=maxn; tot=0; memset(point,0,sizeof(point)); memset(next,0,sizeof(next)); memset(v,0,sizeof(v)); memset(c,0,sizeof(c)); for (int i=1;i<=n;++i) f[i]=i; while (root!=oldroot){ addedge(father[root],root,-1); merge(father[root],root); root=father[root]; } for (int i=1;i<n;++i) if (find(edge[i].x)!=find(edge[i].y)){ addedge(edge[i].x,edge[i].y,1); merge(edge[i].x,edge[i].y); } len2=-INF; treedp(1,0); printf("%d\n",2*(n-1)-len1+1-len2+1); }
相关文章推荐
- android studio 调试service
- Javascript模块化编程(三):require.js的用法
- web.xml中Servlet 配置的四个节点
- nm命令中符号类型详解
- android学习笔记——onSaveInstanceState的使用
- dstat的使用
- IntelliJ Idea 常用快捷键列表
- 深度围观block:第三集
- hdoj 2870 Largest Submatrix 【单调栈】
- android学习日志,点击几次后执行某操作的代码
- 最好的8个Java RESTful框架
- Android 数据库ORM开源框架之greenDAO
- Android Density(密度)
- SVN回退到历史版本
- Caffe安装笔记三:后记
- PyQt5教程——对话框(6)
- HDU-2059 龟兔赛跑( DP )
- 【笔记】关于全栈开发、技术发展方向,软件开发模式的思考
- 什么是大数据思维?
- rt.jar ,dt.jar ,tool.jar都是 做什么用的