题目描述

  题目很长,大家自己去看吧。

  bzoj

  vijos

  原题\(n\leq 300\)

  加强版\(n\leq 500000\)

题解

  这种东西当然要猜结论的啦,否则会比较麻烦。

结论1:如果有很多条直径,那么不管核在哪条直径上,最小偏心距都相同。

结论2 :任意一条路径的偏心距不会小于核的最小偏心距。

  这两个结论的证明方法类似。都是考虑两条路径的公共部分和非公共部分。如果最远的点到路径上的最近的点都在公共部分上,则偏心距相同。任意两条直径的非公共部分长度相同,最远的点到直径上的最近的点的距离显然大于最远的点到其他路径上的最近的点的距离(否则这条直径就不是直径了)。

  结论1告诉我们可以只考虑一条路径,结论2告诉我们可以考虑所有\(O(n^2)\)条路径而不用管这条路径是否在直径上。

  对于\(n\leq 300\),直接暴力枚举路径的两个端点,枚举任意一个点,算出所有其他点到这条路径的距离,就是(这个点到一个端点的距离\(+\)这个点到另一个端点的距离\(-\)这条路径的长度)\(\div 2\),算出最大值然后更新答案。

  算最短路用floyd

  时间复杂度:\(O(n^3)\)

  对于\(n\leq 500000\),找出其中一条直径,把这条直径拿出来,算出每个点往右距离不超过\(s\)的点是哪个,算出每个点忽略直径上左边所有点/右边所有点/左边+右边所有点的最远距离。这三部分的最大值就是一条路径的答案。然后从右往左计算答案,用单调队列维护答案:如果新加入队列的偏心距比队尾的偏心距大,可以把队尾删掉。算出所有路径的答案然后取\(\min\)就可以了。

  时间复杂度:\(O(n)\)

代码

//O(n^3)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<cmath>
#include<functional>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
void sort(int &a,int &b)
{
if(a>b)
swap(a,b);
}
void open(const char *s)
{
#ifndef ONLINE_JUDGE
char str[100];
sprintf(str,"%s.in",s);
freopen(str,"r",stdin);
sprintf(str,"%s.out",s);
freopen(str,"w",stdout);
#endif
}
int rd()
{
int s=0,c;
while((c=getchar())<'0'||c>'9');
do
{
s=s*10+c-'0';
}
while((c=getchar())>='0'&&c<='9');
return s;
}
int upmin(int &a,int b)
{
if(b<a)
{
a=b;
return 1;
}
return 0;
}
int upmax(int &a,int b)
{
if(b>a)
{
a=b;
return 1;
}
return 0;
}
int f[310][310];
int main()
{
int n,s;
scanf("%d%d",&n,&s);
memset(f,0x3f,sizeof f);
int i,x,y,z;
for(i=1;i<n;i++)
{
scanf("%d%d%d",&x,&y,&z);
f[x][y]=f[y][x]=z;
}
for(i=1;i<=n;i++)
f[i][i]=0;
int j,k;
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
if(i!=k)
for(j=1;j<=n;j++)
if(j!=i&&j!=k)
f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
int ans=0x7fffffff;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(f[i][j]<=s)
{
int now=0;
for(k=1;k<=n;k++)
now=max(now,(f[k][i]+f[k][j]-f[i][j])/2);
ans=min(ans,now);
}
printf("%d\n",ans);
return 0;
}
//O(n)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<cmath>
#include<functional>
#include<queue>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
void sort(int &a,int &b)
{
if(a>b)
swap(a,b);
}
void open(const char *s)
{
#ifndef ONLINE_JUDGE
char str[100];
sprintf(str,"%s.in",s);
freopen(str,"r",stdin);
sprintf(str,"%s.out",s);
freopen(str,"w",stdout);
#endif
}
int rd()
{
int s=0,c;
while((c=getchar())<'0'||c>'9');
do
{
s=s*10+c-'0';
}
while((c=getchar())>='0'&&c<='9');
return s;
}
int upmin(int &a,int b)
{
if(b<a)
{
a=b;
return 1;
}
return 0;
}
int upmax(int &a,int b)
{
if(b>a)
{
a=b;
return 1;
}
return 0;
}
struct graph
{
int v[1000010];
int w[1000010];
int t[1000010];
int h[500010];
int n;
graph()
{
memset(h,0,sizeof h);
n=0;
}
void add(int x,int y,int z)
{
n++;
v[n]=y;
w[n]=z;
t[n]=h[x];
h[x]=n;
}
};
graph g;
int from[500010];
int b[500010];
queue<int> q;
int d[500010];
int w[500010];
void bfs(int x)
{
memset(d,-1,sizeof d);
d[x]=0;
q.push(x);
int i;
from[x]=0;
w[x]=0;
while(!q.empty())
{
x=q.front();
q.pop();
for(i=g.h[x];i;i=g.t[i])
if(d[g.v[i]]==-1)
{
d[g.v[i]]=d[x]+g.w[i];
w[g.v[i]]=g.w[i];
from[g.v[i]]=x;
q.push(g.v[i]);
}
}
}
void dfs(int x,int fa,int dep,int &s)
{
s=max(s,dep);
int i;
for(i=g.h[x];i;i=g.t[i])
if(!b[g.v[i]]&&g.v[i]!=fa)
dfs(g.v[i],x,dep+g.w[i],s);
}
int a[500010];
int c[500010];
int f[500010];
int fl[500010];
int fr[500010];
pii q2[500010];
int head,tail;
void add(int x)
{
while(tail>=head&&q2[tail].second<=f[x])
tail--;
q2[++tail]=pii(x,f[x]);
}
void del(int x)
{
if(q2[head].first==x)
head++;
}
int main()
{
freopen("bzoj1999.in","r",stdin);
freopen("bzoj1999.out","w",stdout);
int n,m;
scanf("%d%d",&n,&m);
int i,x,y,z;
for(i=1;i<n;i++)
{
scanf("%d%d%d",&x,&y,&z);
g.add(x,y,z);
g.add(y,x,z);
}
bfs(1);
x=1;
for(i=1;i<=n;i++)
if(d[i]>d[x])
x=i;
bfs(x);
for(i=1;i<=n;i++)
if(d[i]>d[x])
x=i;
int t=0;
do
{
a[++t]=x;
c[t]=w[x];
x=from[x];
}
while(x);
for(i=1;i<=t;i++)
b[a[i]]=1;
int j;
for(i=1;i<=t;i++)
for(j=g.h[a[i]];j;j=g.t[j])
if(!b[g.v[j]])
dfs(g.v[j],0,g.w[j],f[i]);
for(i=1;i<=t;i++)
fl[i]=max(f[i],fl[i-1]+c[i-1]);
for(i=t;i>=1;i--)
fr[i]=max(f[i],fr[i+1]+c[i]);
for(i=1;i<=t;i++)
c[i]+=c[i-1];
head=1;
tail=0;
j=1;
int ans=0x7fffffff;
for(i=1;i<=t;i++)
{
add(i);
while(c[i-1]-c[j-1]>m)
{
del(j);
j++;
}
ans=min(ans,max(max(fl[j],fr[i]),q2[head].second));
}
printf("%d\n",ans);
return 0;
}

【BZOJ1999】【NOIP2007】树网的核 单调队列优化DP的更多相关文章

  1. 单调队列优化DP,多重背包

    单调队列优化DP:http://www.cnblogs.com/ka200812/archive/2012/07/11/2585950.html 单调队列优化多重背包:http://blog.csdn ...

  2. bzoj1855: [Scoi2010]股票交易--单调队列优化DP

    单调队列优化DP的模板题 不难列出DP方程: 对于买入的情况 由于dp[i][j]=max{dp[i-w-1][k]+k*Ap[i]-j*Ap[i]} AP[i]*j是固定的,在队列中维护dp[i-w ...

  3. hdu3401:单调队列优化dp

    第一个单调队列优化dp 写了半天,最后初始化搞错了还一直wa.. 题目大意: 炒股,总共 t 天,每天可以买入na[i]股,卖出nb[i]股,价钱分别为pa[i]和pb[i],最大同时拥有p股 且一次 ...

  4. Parade(单调队列优化dp)

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=2490 Parade Time Limit: 4000/2000 MS (Java/Others)    ...

  5. BZOJ_3831_[Poi2014]Little Bird_单调队列优化DP

    BZOJ_3831_[Poi2014]Little Bird_单调队列优化DP Description 有一排n棵树,第i棵树的高度是Di. MHY要从第一棵树到第n棵树去找他的妹子玩. 如果MHY在 ...

  6. 【单调队列优化dp】 分组

    [单调队列优化dp] 分组 >>>>题目 [题目] 给定一行n个非负整数,现在你可以选择其中若干个数,但不能有连续k个数被选择.你的任务是使得选出的数字的和最大 [输入格式] ...

  7. [小明打联盟][斜率/单调队列 优化dp][背包]

    链接:https://ac.nowcoder.com/acm/problem/14553来源:牛客网 题目描述 小明很喜欢打游戏,现在已知一个新英雄即将推出,他同样拥有四个技能,其中三个小技能的释放时 ...

  8. 单调队列以及单调队列优化DP

    单调队列定义: 其实单调队列就是一种队列内的元素有单调性的队列,因为其单调性所以经常会被用来维护区间最值或者降低DP的维数已达到降维来减少空间及时间的目的. 单调队列的一般应用: 1.维护区间最值 2 ...

  9. BZOJ1791[Ioi2008]Island 岛屿 ——基环森林直径和+单调队列优化DP+树形DP

    题目描述 你将要游览一个有N个岛屿的公园.从每一个岛i出发,只建造一座桥.桥的长度以Li表示.公园内总共有N座桥.尽管每座桥由一个岛连到另一个岛,但每座桥均可以双向行走.同时,每一对这样的岛屿,都有一 ...

随机推荐

  1. Meterpreter常⻅见⽤用法

    0x01 背景 meterpreter作为后渗透模块有多种类型,并且命令由核⼼心命令和扩展库命令组成,极⼤大的丰富了了攻击⽅方式. 需要说明的是meterpreter在漏漏洞洞利利⽤用成功后会发送第二 ...

  2. java 抽象

    MotoVehicle抽象类 package text1; /* * 抽象 */ public abstract class MotoVehicle { // 共同的属性 private String ...

  3. VO和DO转换(三) Dozer

    VO和DO转换(一) 工具汇总 VO和DO转换(二) BeanUtils VO和DO转换(三) Dozer VO和DO转换(四) MapStruct 可参考的资料: dozer官网 Dozer(Jav ...

  4. #Leetcode# 633. Sum of Square Numbers

    https://leetcode.com/problems/sum-of-square-numbers/ Given a non-negative integer c, your task is to ...

  5. scp Permission denied

    https://blog.csdn.net/xlgen157387/article/details/49818259

  6. Use the Microsoft Symbol for VS and Windbg

    快捷方式mklink的远程符号由于所有者权限问题,链接到本地可能造成不能使用, 或每次都需要重新下载, 1.环境变量中没有设置_NT_SYMBOL_PATH的值 2.windbg快捷方式中也没有设置- ...

  7. SQLServer数据库分页

    以  项目表 PM_Project  为例. PM_Project 全部内容如下(共6条数据): 一.Top – Not In - Top 方式分页 直接的,原始的,不采用函数,纯手动挡. 分步探索过 ...

  8. 微信QQ打开网页时提示用浏览器打开

    微信QQ打开网页时提示用浏览器打开 一,需求分析 1.1,使用微信或QQ打开网址时,无法在微信或QQ内打开常用下载软件,手机APP等.故此需要在微信qq里提示 二,功能实现 2.1 html实现 &l ...

  9. scp复制文件到远程服务器上

    scp -P 22 -r 2028792_www  root@120.79.172.45:/usr/local/src Linux scp命令用于Linux之间复制文件和目录. scp是 secure ...

  10. 在linux上安装spark详细步骤

    在linux上安装spark ,前提要部署了hadoop,并且安装了scala. 提君博客原创 对应版本 >>提君博客原创  http://www.cnblogs.com/tijun/   ...