【BZOJ3242】【UOJ#126】【NOI2013】快餐店

NOI都是这种难度的题怎么玩嘛QAQ

原题:

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

N<=10^5,Li<=10^9

 

恩题解比较好理解但是比较难想到……

首先答案不一定是图上的半径,比如酱:

因为有环,所以图上直径的中点到其它所有点距离的最大值可能比半径还要大,这个时候半径就不是最优值

然后显然答案是环上删去某边后树的直径,这个写n^2算法的时候会用到

然后dfs找出环,对环上每个点令其为根求出高度及直径

然后顺着扫一遍,每次记录前面所有环上边的和sum,当前节点子树高度和sum的和的最大值f1,(前面深度最大和次大子树的深度的和)和这两个子树根节点之间的距离的和的最大值f2

然后反过来再搞一遍搞出f3和f4

统计答案即可,注意还有跨过环上第一个点和最后一个点之间的边的情况,这个结合f1和f3就行

最后还要用环上所有点的子树直径的最大值更新ans(不知道为什么QAQ

NOI都是这种难度的题怎么玩嘛QAQ

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 using namespace std;
 7 #define ll long long
 8 int rd(){int z=0,mk=1;  char ch=getchar();
 9     while(ch<'0'||ch>'9'){if(ch=='-')mk=-1;  ch=getchar();}
10     while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0';  ch=getchar();}
11     return z*mk;}
12 struct edg{int nxt,y,v;}e[210000];  int lk[110000],ltp=0;
13 inline void ist(int x,int y,int z){  e[++ltp]=(edg){lk[x],y,z};  lk[x]=ltp;}
14 int n;
15 bool vstd[110000];  int stck[110000],tp=0,fthv[110000];
16 int ccd[110000],cct=0,ccv[110000];
17 ll dp[110000];
18 ll f[110000],f1[110000],f2[110000],f3[110000],f4[110000];
19 ll mxf=0;
20 bool gtcc(int x,int y){
21     stck[++tp]=x;
22     if(vstd[x]){
23         fill(vstd,vstd+1+n,false);
24         do vstd[ccd[++cct]=stck[tp]]=true,ccv[cct]=fthv[stck[tp--]];while(stck[tp]!=x);
25         return true;}
26     vstd[x]=true;
27     for(int i=lk[x];i;i=e[i].nxt)if(e[i].y!=y){
28         fthv[e[i].y]=e[i].v;
29         if(gtcc(e[i].y,x))  return true;}
30     --tp;
31     return false;}
32 void gtdp(int x,int y){
33     for(int i=lk[x];i;i=e[i].nxt)if(e[i].y!=y && !vstd[e[i].y]){
34         dp[e[i].y]=dp[x]+e[i].v,gtdp(e[i].y,x);
35         mxf=max(mxf,f[x]+f[e[i].y]+e[i].v);
36         f[x]=max(f[x],f[e[i].y]+e[i].v);}}
37 int main(){//freopen("ddd.in","r",stdin);
38     int l,r,z;  cin>>n;
39     for(int i=1;i<=n;++i)  l=rd(),r=rd(),z=rd(),ist(l,r,z),ist(r,l,z);
40     if(!gtcc(1,0))  return 0;
41     for(int i=1;i<=cct;++i)  gtdp(ccd[i],0);
42     ll bwl=0,mx=0,ans=0,tt=ccv[cct],tmp;  ccv[cct]=0;
43     for(int i=1;i<=cct;++i){
44         bwl+=ccv[i-1];
45         f1[i]=max(f1[i-1],bwl+f[ccd[i]]);
46         f2[i]=max(f2[i-1],mx+bwl+f[ccd[i]]);
47         mx=max(mx,f[ccd[i]]-bwl);}
48     bwl=mx=0;
49     for(int i=cct;i>=1;--i){
50         bwl+=ccv[i];
51         f3[i]=max(f3[i+1],bwl+f[ccd[i]]);
52         f4[i]=max(f4[i+1],mx+bwl+f[ccd[i]]);
53         mx=max(mx,f[ccd[i]]-bwl);}
54     ans=f2[cct];
55     for(int i=1;i<cct;++i){
56         tmp=max(f1[i]+f3[i+1]+tt,max(f2[i],f4[i+1]));
57         ans=min(ans,tmp);}
58     ans=max(ans,mxf);
59     printf("%.1lf\n",ans*1.0/2);
60     return 0;}
View Code

 

转载于:https://www.cnblogs.com/JSL2018/p/6895415.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BZOJ 2908 题目是一个数据下载任务。这个任务要求下载指定的数据文件,并统计文件中小于等于给定整数的数字个数。 为了完成这个任务,首先需要选择一个合适的网址来下载文件。我们可以使用一个网络爬虫库,如Python中的Requests库,来帮助我们完成文件下载的操作。 首先,我们需要使用Requests库中的get()方法来访问目标网址,并将目标文件下载到我们的本地计算机中。可以使用以下代码实现文件下载: ```python import requests url = '目标文件的网址' response = requests.get(url) with open('本地保存文件的路径', 'wb') as file: file.write(response.content) ``` 下载完成后,我们可以使用Python内置的open()函数打开已下载的文件,并按行读取文件内容。可以使用以下代码实现文件内容读取: ```python count = 0 with open('本地保存文件的路径', 'r') as file: for line in file: # 在这里实现对每一行数据的判断 # 如果小于等于给定整数,count 加 1 # 否则,不进行任何操作 ``` 在每一行的处理过程中,我们可以使用split()方法将一行数据分割成多个字符串,并使用int()函数将其转换为整数。然后,我们可以将该整数与给定整数进行比较,以判断是否小于等于给定整数。 最后,我们可以将统计结果打印出来,以满足题目的要求。 综上所述,以上是关于解决 BZOJ 2908 数据下载任务的简要步骤和代码实现。 希望对您有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值