NOI2013 快餐店

http://uoj.ac/problem/126

总的来说,还是很容易想的,就是有点恶心。

首先,很明显只有一个环。

我们先找出这个环,给各棵树编号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;
  }
View Code

 

posted @ 2015-07-29 07:46  maijing  阅读(1301)  评论(0编辑  收藏  举报