【BZOJ 3242】 (环套树、线段树+树形DP?)

 

 

3242: [Noi2013]快餐店

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 728  Solved: 390

Description

小T打算在城市C开设一家外送快餐店。送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方。 快餐店的顾客分布在城市C的N 个建筑中,这N 个建筑通过恰好N 条双向道路连接起来,不存在任何两条道路连接了相同的两个建筑。任意两个建筑之间至少存在一条由双向道路连接而成的路径。小T的快餐店可以开设在任一建筑中,也可以开设在任意一条道路的某个位置上(该位置与道路两端的建筑的距离不一定是整数)。 现给定城市C的地图(道路分布及其长度),请找出最佳的快餐店选址,输出其与最远的顾客之间的距离。 



Input

第一行包含一个整数N,表示城市C中的建筑和道路数目。
接下来N行,每行3个整数,Ai,Bi,Li(1≤i≤N;Li>0),表示一条道路连接了建筑Ai与Bi,其长度为Li 。

Output

仅包含一个实数,四舍五入保留恰好一位小数,表示最佳快餐店选址距离最远用户的距离。
注意:你的结果必须恰好有一位小数,小数位数不正确不得分。

Sample Input

1 2 1
1 4 2
1 3 2
2 4 1

Sample Output

2.0

HINT


数据范围

对于 10%的数据,N<=80,Li=1; 

对于 30%的数据,N<=600,Li<=100; 

对于 60% 的数据,N<=2000,Li<=10^9; 

对于 100% 的数据,N<=10^5,Li<=10^9

Source

 

 

【分析】

  这题好难啊。。

 

  首先是,显然求的是树上的最长链。但是这是一个环套树。

  对于基环树上的点,求出他们两两间的最长链,这个用树形DP,其实dfs一遍就好了。

  当然也是可以走环的,如果走环的话,环可以走两边,肯定选了最近的一边走了。这个最长链一定是断掉环的某边之后那棵树的最长链。

  所以可以枚举断掉环上某条边。问现在的最长链,取最优那个即可。

  这个怎么做呢?

 

  求出f[i]表示i是环上一点,他的基环树向下的最长链是f[i]。

  假设断掉了某条边,环变成了链,那么记录一个sm[i]表示到左端点的距离

  对于环上两点i,j,则最长链有sm[j]-sm[i]+f[i]+f[j]=(f[i]-sum[i])+(sm[j]+f[j])

  就是维护两个东西,f[i]-sum[i]和f[i]+sm[i],选两个最大的加起来。

  但是这两个最大的不能是同一个id,所以还要维护次大值。

  当你枚举另一条断边的时候,只要修改一个sm值就好了。

  【一开始LL没开,INF太小哭。。【然后一生气又全开LL了ORZ

 

 

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 using namespace std;
  7 #define Maxn 100010
  8 // #define INF 0x7fffffff
  9 #define LL long long
 10 const LL INF=1LL<<60;
 11 
 12 LL mymax(LL x,LL y) {return x>y?x:y;}
 13 LL mymin(LL x,LL y) {return x<y?x:y;}
 14 
 15 LL n,r1[Maxn],r2[Maxn],rr[Maxn],nc[Maxn];
 16 LL cc[Maxn];
 17 
 18 struct node
 19 {
 20     LL x,y,c,next;
 21 }t[Maxn*2];
 22 LL first[Maxn],len;
 23 LL fa[Maxn];
 24 
 25 LL ffa(LL x)
 26 {
 27     if(fa[x]!=x) fa[x]=ffa(fa[x]);
 28     return fa[x];
 29 }
 30 
 31 void ins(LL x,LL y,LL c)
 32 {
 33     t[++len].x=x;t[len].y=y;t[len].c=c;
 34     t[len].next=first[x];first[x]=len;
 35 }
 36 
 37 LL cr[Maxn];
 38 
 39 bool dfs(LL x,LL ff,LL nw)
 40 {
 41     if(x==r2[nw]) {cr[++cr[0]]=x;cc[cr[0]]=nc[nw];return 1;}
 42     for(LL i=first[x];i;i=t[i].next) if(t[i].y!=ff)
 43     {
 44         if(dfs(t[i].y,x,nw)) {cr[++cr[0]]=x;cc[cr[0]]=t[i].c;return 1;} 
 45     }
 46     return 0;
 47 }
 48 
 49 bool vis[Maxn];
 50 LL ln[Maxn];
 51 
 52 struct nnode
 53 {
 54     LL l,r,lc,rc;
 55     LL mx1,mx2,m1,m2,id1,id2;
 56 }tr[Maxn*2];
 57 
 58 void upd(LL x)
 59 {
 60     LL lc=tr[x].lc,rc=tr[x].rc;
 61     tr[x].mx1=mymax(tr[lc].mx1,tr[rc].mx1);
 62     tr[x].id1=tr[lc].mx1>tr[rc].mx1?tr[lc].id1:tr[rc].id1;
 63     tr[x].mx2=tr[lc].mx1>tr[rc].mx1?mymax(tr[lc].mx2,tr[rc].mx1):mymax(tr[lc].mx1,tr[rc].mx2);
 64     
 65     tr[x].m1=mymax(tr[lc].m1,tr[rc].m1);
 66     tr[x].id2=tr[lc].m1>tr[rc].m1?tr[lc].id2:tr[rc].id2;
 67     tr[x].m2=tr[lc].m1>tr[rc].m1?mymax(tr[lc].m2,tr[rc].m1):mymax(tr[lc].m1,tr[rc].m2);
 68 }
 69 
 70 LL tot=0,sm[Maxn];
 71 LL build(LL l,LL r,LL nw)
 72 {
 73     LL x=++tot;
 74     tr[x].l=l;tr[x].r=r;
 75     if(l==r)
 76     {
 77         LL id=l+rr[nw-1];
 78         tr[x].mx1=ln[cr[id]]+sm[id];tr[x].mx2=-INF;
 79         tr[x].m1=ln[cr[id]]-sm[id];tr[x].m2=-INF;
 80         tr[x].id1=tr[x].id2=l;
 81         tr[x].lc=tr[x].rc=0;
 82     }
 83     else
 84     {
 85         LL mid=(l+r)>>1;
 86         tr[x].lc=build(l,mid,nw);
 87         tr[x].rc=build(mid+1,r,nw);
 88         upd(x);
 89     }
 90     return x;
 91 }
 92 
 93 LL g[Maxn];
 94 void get_l(LL x,LL ff)
 95 {
 96     ln[x]=0;LL mx1=0,mx2=0;
 97     g[x]=0;
 98     for(LL i=first[x];i;i=t[i].next) if(t[i].y!=ff&&vis[t[i].y])
 99     {
100         LL y=t[i].y;
101         get_l(y,x);
102         if(ln[y]+t[i].c>mx1) mx2=mx1,mx1=ln[y]+t[i].c;
103         else if(ln[y]+t[i].c>mx2) mx2=ln[y]+t[i].c;
104         g[x]=mymax(g[x],g[y]);
105     }
106     g[x]=mymax(g[x],mx1+mx2);
107     ln[x]=mx1;
108 }
109 
110 void change(LL x,LL y,LL nw)
111 {
112     if(tr[x].l==tr[x].r)
113     {
114         LL id=y+rr[nw-1];
115         tr[x].mx1=sm[id]+ln[cr[id]];
116         tr[x].m1=ln[cr[id]]-sm[id];
117         return;
118     }
119     LL mid=(tr[x].l+tr[x].r)>>1;
120     if(y<=mid) change(tr[x].lc,y,nw);
121     else change(tr[x].rc,y,nw);
122     upd(x);
123 }
124 
125 LL get_ans()
126 {
127     if(tr[1].id1!=tr[1].id2) return tr[1].mx1+tr[1].m1;
128     else return mymax(tr[1].mx1+tr[1].m2,tr[1].mx2+tr[1].m1);
129 }
130 
131 int main()
132 {
133     scanf("%lld",&n);
134     len=0;
135     for(LL i=1;i<=n;i++) fa[i]=i;
136     LL cnt=0;
137     for(LL i=1;i<=n;i++)
138     {
139         LL x,y,c;
140         scanf("%lld%lld%lld",&x,&y,&c);
141         if(ffa(x)==ffa(y))
142         {
143             r1[++cnt]=x;r2[cnt]=y;
144             nc[cnt]=c;
145         }
146         else
147         {
148             fa[ffa(x)]=ffa(y);
149             ins(x,y,c);ins(y,x,c);
150         }
151         
152     }
153     cr[0]=0;rr[0]=0;
154     for(LL i=1;i<=cnt;i++) 
155     {
156         dfs(r1[i],0,i);
157         rr[i]=rr[i-1]+cr[0];
158     }
159     memset(vis,1,sizeof(vis));
160     for(LL i=1;i<=cr[0];i++) vis[cr[i]]=0;
161     LL ans=0;
162     for(LL i=1;i<=cr[0];i++)
163     {
164         get_l(cr[i],0);
165         ans=mymax(ans,g[cr[i]]);
166     }
167     for(LL i=1;i<=cnt;i++)
168     {
169         sm[rr[i-1]+1]=0;
170         LL mn=INF;
171         
172         for(LL j=rr[i-1]+2;j<=rr[i];j++) sm[j]=sm[j-1]+cc[j];
173         
174         build(1,rr[i]-rr[i-1],i);
175         mn=mymin(mn,get_ans());
176         for(LL j=rr[i-1]+1;j<rr[i];j++)
177         {
178             LL p=j,q=p-1;
179             if(j==rr[i-1]+1) q=rr[i];
180             sm[p]=sm[q]+cc[p];
181             
182             change(1,p-rr[i-1],i);
183             mn=mymin(mn,get_ans());
184         }
185         ans=mymax(ans,mn);
186     }
187     printf("%.1lf\n",ans*1.0/2);
188     return 0;
189 }
View Code

 

2017-03-25 11:57:32

posted @ 2017-03-25 11:57  konjak魔芋  阅读(244)  评论(0编辑  收藏  举报