NOI2013 快餐店
总的来说,还是很容易想的,就是有点恶心。
首先,很明显只有一个环。
我们先找出这个环,给各棵树编号id[i],然后各棵树分别以环上的点为根,求出每个点的深度dep[i],根节点st[i],最深的孩子的深度furthestson[i]和不进入子树最远的点距离f[i],这些都比较好求。
我们分2种情况讨论:
(1)快餐店在环上
将环上的点以furthestson[i]为权值,等价于快餐店到点的最短距离再加上点的权值的最大值最小。
其实我们可以将这个环看成一个正圆,过快餐店的一条直径将这个圆分成2部分,快餐店顺时针到左边的点,逆时针到右边的点,我们分别将左边的点和右边的点分别放在2个单调队列中。
当我们逆时针旋转这条直径的时候,左右两边是单调的,可以用单调队列,然后更新答案即可。
(2)快餐店在树上
我们在(1)中顺便记录一下第i棵树不进入本树可以到达的最远距离h[i]
我们枚举树边(u,v),不失一般性,dep[u]<dep[v],且其长度为l。
那么这条路径v那一端最远可以到的距离为furthestson[v],u那一端最远可以到的距离为max(f[v]-l,dep[u]+h[id[st[u]]])。
然后更新答案即可。
#include<cstdio> #include<cstdlib> #include<iostream> #include<fstream> #include<algorithm> #include<cstring> #include<string> #include<cmath> #include<queue> #include<stack> #include<map> #include<utility> #include<set> #include<bitset> #include<vector> #include<functional> #include<deque> #include<cctype> #include<climits> #include<complex> //#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj using namespace std; typedef long long LL; typedef double DB; typedef pair<int,int> PII; typedef complex<DB> CP; #define mmst(a,v) memset(a,v,sizeof(a)) #define mmcy(a,b) memcpy(a,b,sizeof(a)) #define re(i,a,b) for(i=a;i<=b;i++) #define red(i,a,b) for(i=a;i>=b;i--) #define fi first #define se second #define m_p(a,b) make_pair(a,b) #define SF scanf #define PF printf #define two(k) (1<<(k)) template<class T>inline T sqr(T x){return x*x;} template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;} template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;} const DB EPS=1e-9; inline int sgn(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;} const DB Pi=acos(-1.0); inline void clear(vector<int> *A,int a,int b){int i,j;A->clear();re(i,0,a)re(j,0,b)A[i].push_back(0);} inline int gint() { int res=0;bool neg=0;char z; for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar()); if(z==EOF)return 0; if(z=='-'){neg=1;z=getchar();} for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar()); return (neg)?-res:res; } inline LL gll() { LL res=0;bool neg=0;char z; for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar()); if(z==EOF)return 0; if(z=='-'){neg=1;z=getchar();} for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar()); return (neg)?-res:res; } const int maxN=100000; int N; int now,first[maxN+100]; struct Tedge{int u,v,next,dis;}edge[2*maxN+100]; DB ans; inline void addedge(int u,int v,int dis) { now++; edge[now].u=u; edge[now].v=v; edge[now].dis=dis; edge[now].next=first[u]; first[u]=now; } #define next(i) (i%cnt+1) #define qian(i) ((i-2+cnt)%cnt+1) int cnt,root[maxN+10]; LL lon[maxN+10]; int id[maxN+100]; int vis[maxN+10]; int fa[maxN+100]; int sta[maxN+10],last[maxN+10],top; inline void DFS() { mmst(vis,0); mmst(fa,0); vis[sta[top=1]=1]=1; last[1]=first[1]; while(top>=1) { int u=sta[top],i=last[top],v; for(v=edge[i].v;i!=-1;i=edge[i].next,v=edge[i].v) { if(!vis[v]) { last[top]=edge[i].next; vis[sta[++top]=v]=1; last[top]=first[v]; fa[v]=u; break; } if(vis[v] && v!=fa[u]) { while(sta[top]!=v)root[++cnt]=sta[top--]; root[++cnt]=v; return; } } if(i==-1)top--; } } inline void findround() { int i,j; DFS(); re(i,1,cnt) { id[root[i]]=i; int v,dis; for(j=first[root[i]],v=edge[j].v,dis=edge[j].dis;j!=-1;j=edge[j].next,v=edge[j].v,dis=edge[j].dis) if(v==root[next(i)]){lon[i]=LL(dis);break;} } } int head,tail,que[maxN+100]; LL dep[maxN+100],furthestson[maxN+100],f[maxN+100]; int st[maxN+100]; inline void solve1(int rt) { int i,j; vis[que[head=tail=1]=rt]=1; dep[rt]=0; fa[rt]=0; while(head<=tail) { int u=que[head++],v,dis; for(i=first[u],v=edge[i].v,dis=edge[i].dis;i!=-1;i=edge[i].next,v=edge[i].v,dis=edge[i].dis) if(id[v]==0 && !vis[v]) { fa[v]=u; vis[que[++tail]=v]=1; dep[v]=dep[u]+LL(dis); } } red(j,tail,1) { int u=que[j],v,dis; furthestson[u]=0; for(i=first[u],v=edge[i].v,dis=edge[i].dis;i!=-1;i=edge[i].next,v=edge[i].v,dis=edge[i].dis) if(id[v]==0 && v!=fa[u]) upmax(furthestson[u],furthestson[v]+LL(dis)); } f[rt]=0; re(j,1,tail) { int u=que[j],v,dis;LL maxv1=0,maxv2=0;int hea=-1; for(i=first[u],v=edge[i].v,dis=edge[i].dis;i!=-1;i=edge[i].next,v=edge[i].v,dis=edge[i].dis) if(id[v]==0 && v!=fa[u]) { if(furthestson[v]+LL(dis)>maxv1) maxv2=maxv1,maxv1=furthestson[v]+LL(dis),hea=v; else if(furthestson[v]+LL(dis)>maxv2) maxv2=furthestson[v]+LL(dis); } for(i=first[u],v=edge[i].v,dis=edge[i].dis;i!=-1;i=edge[i].next,v=edge[i].v,dis=edge[i].dis) if(id[v]==0 && v!=fa[u]) { if(v!=hea) f[v]=LL(dis)+max(f[u],maxv1); else f[v]=LL(dis)+max(f[u],maxv2); } } re(i,1,tail)st[que[i]]=rt; } DB h[maxN+100]; struct Tque { int head,tail; DB add,que[2*maxN+100],idx[2*maxN+10];////////////////注意,要2倍空间!!!!!!!!!!!!!!!!!!!! inline void clear(){head=1;tail=0;add=0.0;} inline void insert(int id,DB v) { ++tail;que[tail]=v-add;idx[tail]=id; while(tail-head+1>=2 && que[tail]>que[tail-1])que[tail-1]=que[tail],idx[tail-1]=idx[tail],tail--; } inline void erase(int id){if(idx[head]==id)head++;} inline DB maxv(){return tail-head+1>=1?que[head]+add:0.0;} }Q1,Q2; DB cir,pos[maxN+10]; inline DB dist(DB p1,DB p2){return p2>=p1 ? p2-p1 : cir+p2-p1; } inline void move(DB &w,DB l){w+=l;if(w>=cir) w-=cir;} inline void solve2() { int i,p1,p2; DB w1,w2; cir=0.0;re(i,1,cnt)pos[i]=cir,cir+=DB(lon[i]); p1=1; for(p2=1;pos[p2]<=cir/2.0 && p2!=cnt;p2=next(p2)); if(p2==cnt && pos[p2]<=cir/2.0)p2=next(p2); Q1.clear();Q2.clear(); re(i,p1,qian(p2))Q1.insert(i,DB(furthestson[root[i]])+pos[i]); if(p2!=p1) re(i,p2,qian(p1))Q2.insert(i,DB(furthestson[root[i]])+cir-pos[i]); w1=0.0;w2=cir/2.0; mmst(vis,0); vis[1]=1; while(vis[2]<2) if(dist(w2,pos[p2])<=dist(w1,pos[p1])) { DB l=dist(w2,pos[p2]); Q1.add-=l; DB v1=Q1.maxv(),v2=Q2.maxv(); upmin(ans,max(v1,v2+l)); upmin(ans,max(v2,v1+l)); if(v1<=(v1+l+v2)/2.0 && (v1+l+v2)/2.0<=v1+l) upmin(ans,(v1+l+v2)/2.0); Q2.erase(p2); Q2.add+=l; move(w1,l); move(w2,l); Q1.insert(p2,DB(furthestson[root[p2]])+dist(w1,pos[p2])); p2=next(p2); } else { DB l=dist(w1,pos[p1]); Q1.add-=l; DB v1=Q1.maxv(),v2=Q2.maxv(); upmin(ans,max(v1,v2+l)); upmin(ans,max(v2,v1+l)); if(v1<=(v1+l+v2)/2.0 && (v1+l+v2)/2.0<=v1+l) upmin(ans,(v1+l+v2)/2.0); Q1.erase(p1); Q2.add+=l; move(w1,l); move(w2,l); h[p1]=max(Q1.maxv(),Q2.maxv()); Q2.insert(p1,DB(furthestson[root[p1]])+dist(pos[p1],w1)); p1=next(p1); vis[p1]++; } } inline void solve3() { int i; re(i,0,now) { int u=edge[i].u,v=edge[i].v;DB l=DB(edge[i].dis); if(id[u]!=0 && id[v]!=0)continue; if(dep[u]>dep[v]) swap(u,v); DB v1=DB(furthestson[v]),v2=max(DB(f[v])-l,DB(dep[u])+h[id[st[u]]]); upmin(ans,max(v1,v2+l)); upmin(ans,max(v2,v1+l)); if(v1<=(v1+l+v2)/2.0 && (v1+l+v2)/2.0<=v1+l) upmin(ans,(v1+l+v2)/2.0); } } int main() { /*freopen("foodshop.in","r",stdin); freopen("foodshop.out","w",stdout);*/ int i; N=gint(); now=-1;mmst(first,-1); re(i,1,N) { int u=gint(),v=gint(),dis=gint(); addedge(u,v,dis); addedge(v,u,dis); } findround(); mmst(vis,0); re(i,1,cnt)solve1(root[i]); ans=1e60; solve2(); solve3(); PF("%0.1lf\n",ans); return 0; }