【BZOJ1999】树网的核,求树的直径+单调队列乱搞
2016-09-12 21:53
381 查看
传送门
思路:
很好的一道乱搞题
原来的题目我写的是O(n3)的
由于n<=500000
所以我们可以猜一些结论来减少时间复杂度
比如说每个直径都有最小偏心距,直径上每个点的偏心距可以快速处理,在直径上时[L,R]的偏心距一定小于等于[l,r]其中L<=l<=r<=R
关于直径上每个点的偏心距,有一个很好的处理方法
以这个点为根,在不经过直径的情况下遍历所有能到达的点,计算出最大距离dis
那么它的偏心距就是max(dis,到直径左端点距离,到右端点距离)
这个结论比较显然,但不是很好想到
然后就可以随便找一条直径,预处理出dis,然后一段段从前向后枚举求答案了
用单调队列维护
复杂度O(n)
求直径跑两次bfs即可,网上有详细说明,不再赘述
思路:
很好的一道乱搞题
原来的题目我写的是O(n3)的
由于n<=500000
所以我们可以猜一些结论来减少时间复杂度
比如说每个直径都有最小偏心距,直径上每个点的偏心距可以快速处理,在直径上时[L,R]的偏心距一定小于等于[l,r]其中L<=l<=r<=R
关于直径上每个点的偏心距,有一个很好的处理方法
以这个点为根,在不经过直径的情况下遍历所有能到达的点,计算出最大距离dis
那么它的偏心距就是max(dis,到直径左端点距离,到右端点距离)
这个结论比较显然,但不是很好想到
然后就可以随便找一条直径,预处理出dis,然后一段段从前向后枚举求答案了
用单调队列维护
复杂度O(n)
求直径跑两次bfs即可,网上有详细说明,不再赘述
#include<cstdio> #include<iostream> #include<queue> #include<cstring> #define M 500005 using namespace std; int n,s,tot,S,T,ans=1<<30; int dis[M],first[M],up[M],mx[M],D[M],q[M]; bool vis[M]; int in() { char ch=getchar();int t=0; while (ch<'0'||ch>'9') ch=getchar(); while (ch>='0'&&ch<='9') t=(t<<1)+(t<<3)+ch-48,ch=getchar(); return t; } struct edge{ int v,next,w; }e[M<<1]; void add(int z,int x,int y) { e[++tot]=(edge){y,first[x],z};first[x]=tot; e[++tot]=(edge){x,first[y],z};first[y]=tot; } int bfs(int s) { queue<int>q; while (!q.empty()) q.pop(); q.push(s); up[s]=0; for (;!q.empty();q.pop()) { int x=q.front(); for (int i=first[x];i;i=e[i].next) if (!dis[e[i].v]&&e[i].v!=s) dis[e[i].v]=dis[x]+e[i].w, q.push(e[i].v), up[e[i].v]=x; } int t=1; for (int i=2;i<=n;++i) if (dis[i]>dis[t]) t=i; return t; } void bfs2(int i) { queue<int>q; while (!q.empty()) q.pop(); q.push(i); for (;!q.empty();q.pop()) { int x=q.front(); for (int j=first[x];j;j=e[j].next) if (!vis[e[j].v]&&!D[e[j].v]) D[e[j].v]=D[x]+e[j].w, q.push(e[j].v), mx[i]=max(mx[i],D[e[j].v]); } } main() { n=in();s=in(); for (int i=1;i<n;++i) add(in(),in(),in()); S=bfs(1); memset(dis,0,sizeof(dis)); T=bfs(S); for (int i=T;i;i=up[i]) vis[i]=1; for (int i=T;i;i=up[i]) bfs2(i); int L=T,R=T,head=1,tail=1; q[1]=T; for (;L;L=up[L]) { while (up[R]&&dis[L]-dis[up[R]]<=s) { R=up[R]; while (head<=tail&&mx[q[tail]]<=mx[R]) --tail; q[++tail]=R; ans=min(ans,max(mx[q[head]],max(dis[R]-dis[S],dis[T]-dis[L]))); } if (q[head]==L) ++head; } printf("%d\n",ans); }
相关文章推荐
- 【bzoj1999】[Noip2007]Core树网的核 树的直径+双指针法+单调队列
- bzoj 1999: [Noip2007]Core树网的核【树的直径+单调队列】
- BZOJ 1999 [Noip2007]树网的核(2282 [Sdoi2011]消防) - 树的直径+单调队列
- bzoj1999 [Noip2007]Core树网的核(树的直径+单调队列+贪心)
- BZOJ_1999_[Noip2007]Core树网的核_单调队列+树形DP
- [仙人掌直径 单调队列 DP] BZOJ 1023 [SHOI2008]cactus仙人掌图
- bzoj1990 NOIP2007 树网的核 树的直径&单调队列维护最小值
- 【BZOJ】1999 [Noip2007]Core树网的核 树的直径+DFS
- [树的直径] BZOJ 1999 [Noip2007]Core树网的核
- 【bzoj 1293】[SCOI2009]生日礼物(乱搞|单调队列)
- [BZOJ]2282: [Sdoi2011]消防 树的直径+单调队列
- 1999: [Noip2007]Core树网的核 树形dp 单调队列
- 【BZOJ1999】【NOIP2007】树网的核 单调队列优化DP
- 【BZOJ2282】【Sdoi2011】消防 树的直径+双指针+单调队列 有一系列乱七八糟的证明
- 【BZOJ】【P1113】【Poi2008】【海报PLA】【题解】【单调队列】
- bzoj 1047 单调队列
- [BZOJ1047][HAOI2007]理想的正方形(单调队列)
- [BZOJ 2442][Usaco2011 Open]修剪草坪:单调队列
- bzoj 1293: [SCOI2009]生日礼物 (单调队列)
- [BZOJ 1499][NOI 2005]瑰丽华尔兹(DP+单调队列优化)