bzoj 3743 kmap
2015-11-16 10:40
323 查看
这道题首先找出来虚树,算出虚树的边的总长。这样虚树内的点的答案就是总长*2-虚树中距它最远点的距离。然后距它最远点的距离是直径上的点。虚树外的点就是找到距它最近的虚树内的点的答案加上这个距离。开始的时候我按照奶牛集会的那道题写了。
#include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #define ll long long #define inf 1e9 #define eps 1e-10 #define md #define N 500010 using namespace std; struct yts { int x,t,ne,l;} e[2*N]; int v ; ll dis ,sig ,dis1 ,dis2 ,cnt ,ans ; int bl ; bool blo ,vis ; int rt,R1,R2,n,K,num=0; void put(int x,int y,int l) { num++; e[num].x=x; e[num].t=y; e[num].l=l; e[num].ne=v[x]; v[x]=num; } void dfs1(int x,int fa) { for (int i=v[x];i;i=e[i].ne) { int y=e[i].t; if (y!=fa) { dis[y]=dis[x]+1; dfs1(y,x); cnt[x]+=cnt[y]; sig[x]+=sig[y]+(cnt[y]>0?e[i].l:0); } } } void dfs2(int x,int fa) { blo[x]=1; for (int i=v[x];i;i=e[i].ne) { int y=e[i].t; if (y!=fa&&cnt[y]&&dis[y]>dis[x]) dfs2(y,x); } } void dfs3(int x,int fa) { for (int i=v[x];i;i=e[i].ne) { int y=e[i].t; if ((blo[y])&&y!=fa) { dis1[y]=dis1[x]+e[i].l; dfs3(y,x); } } } void get_R() { memset(dis1,0,sizeof(dis1)); dfs3(rt,0);//找出到x的距离 R2=rt; for (int i=1;i<=n;i++) { if (blo[i]&&dis1[i]>dis1[R2]) R2=i; } memset(dis1,0,sizeof(dis1)); dfs3(R2,0); R1=rt; for (int i=1;i<=n;i++) { if (blo[i]) { if (dis1[i]>dis1[R1]) R1=i; dis2[i]=dis1[i]; } } memset(dis1,0,sizeof(dis1)); dfs3(R1,0); } void dfs4(int x,int fa,int rot) { vis[x]=1; for (int i=v[x];i;i=e[i].ne) { int y=e[i].t; if ((!vis[y])&&(!blo[y])) { dis[y]=dis[x]+e[i].l; bl[y]=rot; dfs4(y,x,rot); } } } void dfs5(int x,int fa) { for (int i=v[x];i;i=e[i].ne) { int y=e[i].t; if (y!=fa&&(blo[y])) { ans[y]=ans[x]; dfs5(y,x); } } } void dp() { ans[rt]=sig[rt]; dfs5(rt,0); //虚树的奶牛集会 for (int i=1;i<=n;i++) { if (blo[i]) ans[i]=ans[i]*2-max(dis1[i],dis2[i]); } for (int i=1;i<=n;i++) { if (!blo[i]) ans[i]=ans[bl[i]]+dis[i]; } } int main() { scanf("%d%d",&n,&K); for (int i=1;i<=n-1;i++) { int x,y,l; scanf("%d%d%d",&x,&y,&l); put(x,y,l); put(y,x,l); } for (int i=1;i<=K;i++) { int x; scanf("%d",&x); cnt[x]++; } dfs1(1,0);//统计cnt,sig rt=1; for (int i=2;i<=n;i++) if (cnt[i]==K&&dis[rt]<dis[i]) rt=i; dfs2(rt,0);//找出虚树 get_R(); memset(dis,0,sizeof(dis)); for (int i=1;i<=n;i++) if (blo[i]&&(!vis[i])) dfs4(i,0,i);//找到不在虚树中点到虚树的距离 dp(); for (int i=1;i<=n;i++) printf("%lld\n",ans[i]); return 0; }
相关文章推荐
- dp专题训练
- bzoj 1060 时态同步 水题?神题?
- 练贪心!贪心!贪心!
- bzoj 3175 攻击装置 | 二分图最大独立集
- 图解javascript this指向什么?
- 远程控制电脑
- Linux Basics command
- java http 请求方法
- .ajax设置成同步的应用场景
- java泛型编程
- linux下apache2两种工作模式及两者切换
- bzoj 3032 七夕祭 | 中位数
- bzoj 2594 水管局长 | LCT | 最小生成树
- bzoj 3706 反色刷 | 一笔画
- bzoj 3108 图的逆变换
- bzoj 2660 最多的方案 | 斐波那契数列
- bzoj 1187 神奇的游乐园 | 插头dp
- bzoj 2173 整数的lqp拆分 | dp | 找规律
- poj 2411| 插头dp
- bzoj 2660 最多的方案 | dp