【bzoj2282】[Sdoi2011]消防

两次bfs可得直径,答案一定不会小于所有点到直径的距离最大值,只要把直径上的边权设为0,任选直径上一点bfs可得将最大值作为二分下界,二分直径左右端点的舍弃部分

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;

#define N 300010

struct edge
{
    int to,next,w;
}e[N<<1];
int head[N<<1];
int cnt;

int n,s;

int rt,x,y,z;

int maxn,top,D;

int st[N],from[N],mark[N],dis[N];//,q[N];

queue<int>q;

void link(int x,int y,int z)
{
    e[++cnt]=(edge){y,head[x],z};
    head[x]=cnt;
}

void bfs(int x)
{
    for (int i=1;i<=n;i++)
        dis[i]=-1;
    q.push(x);
    dis[x]=0;
    while (!q.empty())
    {
        int now=q.front();
        q.pop();
        for (int i=head[now];i;i=e[i].next)
        {
            int t=e[i].to;
            if (dis[t]==-1)
            {
                from[t]=now;
                if (mark[t])
                    dis[t]=dis[now];
                else
                    dis[t]=dis[now]+e[i].w;
                q.push(t);
            }
        }
    }
}

bool work(int d)
{
    int l=1,r=top;
    while (st[1]-st[l+1]<=d && l<=top)
        l++;
    while (st[r-1]<=d && r>=1)
        r--;
    return st[l]-st[r]<=s;
}
int main()
{
    scanf("%d%d",&n,&s);
    for (int i=1;i<n;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        link(x,y,z);
        link(y,x,z);
    }
    bfs(1);
    for (int i=1;i<=n;i++)
        if (dis[rt]<dis[i])
            rt=i;
    bfs(rt);
    for (int i=1;i<=n;i++)
        if (dis[x]<dis[i])
            x=i;
    D=dis[x];
    st[++top]=dis[x];
    mark[x]=1;
    while (x!=rt)
    {
        st[++top]=dis[from[x]];
        x=from[x];
        mark[x]=1;
    }
    bfs(x);
    int l=0,r=D;
    for(int i=1;i<=n;i++)
        l=max(l,dis[i]);
    if (s<D)
        while (l<=r)
        {
            int mid=(l+r)>>1;
            if (work(mid))
                r=mid-1;
            else
                l=mid+1;
        }
    printf("%d\n",l);
    return 0;
}

  

时间: 2024-10-29 19:09:55

【bzoj2282】[Sdoi2011]消防的相关文章

bzoj2282[Sdoi2011]消防

bzoj2282[Sdoi2011]消防 题意: 在树上找一条路径,使得端点到这条路径的距离最大值最小. 题解: 一个坑,就是这个路径可以不包含任意一条边,只包含一个节点.因此可以证明这条路径在树的直径上,把树的直径上的所有边存入一个序列,对直径上每个点求其它不在路径上的点与它的最大距离mxd,然后用双指针维护序列的一段使得和≤s,比较答案和序列两端到直径首末端的距离及序列中的点的最大mxd的较大值.序列中的点的最大mxd值用单调队列即可维护,怎么求树的直径呢?先对任意节点dfs/bfs求出最大

【BZOJ2282】[Sdoi2011]消防 树形DP+双指针法+单调队列

[BZOJ2282][Sdoi2011]消防 Description 某个国家有n个城市,这n个城市中任意两个都连通且有唯一一条路径,每条连通两个城市的道路的长度为zi(zi<=1000). 这个国家的人对火焰有超越宇宙的热情,所以这个国家最兴旺的行业是消防业.由于政府对国民的热情忍无可忍(大量的消防经费开销)可是却又无可奈何(总统竞选的国民支持率),所以只能想尽方法提高消防能力. 现在这个国家的经费足以在一条边长度和不超过s的路径(两端都是城市)上建立消防枢纽,为了尽量提高枢纽的利用率,要求其

[SDOI2011]消防

题目描述 某个国家有n个城市,这n个城市中任意两个都连通且有唯一一条路径,每条连通两个城市的道路的长度为zi(zi<=1000). 这个国家的人对火焰有超越宇宙的热情,所以这个国家最兴旺的行业是消防业.由于政府对国民的热情忍无可忍(大量的消防经费开销)可是却又无可奈何(总统竞选的国民支持率),所以只能想尽方法提高消防能力. 现在这个国家的经费足以在一条边长度和不超过s的路径(两端都是城市)上建立消防枢纽,为了尽量提高枢纽的利用率,要求其他所有城市到这条路径的距离的最大值最小. 你受命监管这个项目

P1099 树网的核 &amp;&amp; P2491 [SDOI2011]消防

给定一棵树, 你可以在树的直径上确定一条长度不超过 \(S\) 的链, 使得树上离此链最长的点距离最小, 输出这个距离 P2491 数据范围为 P1099 的 \(1000\) 倍 Solution 首先两次 \(dfs\) 确定树的直径, 即第一次随意从某一点出发到达最远点记为 \(s\), 第二次从 \(s\) 出发到达最远点 \(t\) , 则 \(s-t\) 即为树的直径 现在我们得到了直径, 试想树上现在有一条链, 包含点 \(a_{1},a_{2}...a_{n}\), 树上到此链最

贪心(qwq)习题题解

贪心(qwq)习题题解 SCOI 题解 [ SCOI2016 美味 ] 假设已经确定了前i位,那么答案ans一定属于一个区间. 从高位往低位贪心,每次区间查找是否存在使此位答案为1的值. 比如6位数确定了前三位\((101...)_2\),下一位应该是1 那么\(a_i+x_i\)的查找区间为:\([(101100)_2,(101111)_2]\) ,同理如果应该是0则为\([(101000)_2,(101011)_2]\). 注意到有区间\([l,r]\)范围的限制所以用主席树维护即可. [

【SDOI2011 第2轮 DAY1】消防 [解题报告]

[SDOI2011 第2轮 DAY1]消防 题面: SDOI2011 第2轮 DAY1]消防 时间限制 : 20000 MS 空间限制 : 565536 KB 问题描述 时限\(2s\) 某个国家有\(n\)个城市,这\(n\)个城市中任意两个都连通且有唯一一条路径,每条连通两个城市的道路的长度为\(zi(zi<=1000)\). 这个国家的人对火焰有超越宇宙的热情,所以这个国家最兴旺的行业是消防业.由于政府对国民的热情忍无可忍(大量的消防经费开销)可是却又无可奈何(总统竞选的国民支持率),所以

bzoj2242: [SDOI2011]计算器.

2242: [SDOI2011]计算器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 4353  Solved: 1679[Submit][Status][Discuss] Description 你被要求设计一个计算器完成以下三项任务: 1.给定y,z,p,计算Y^Z Mod P 的值: 2.给定y,z,p,计算满足xy≡ Z ( mod P )的最小非负整数: 3.给定y,z,p,计算满足Y^x ≡ Z ( mod P)的最小非负整数. In

BZOJ 2243: [SDOI2011]染色 树链剖分

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1886  Solved: 752[Submit][Status] Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完成这m个操作. In

bzoj 2243: [SDOI2011]染色 线段树区间合并+树链剖分

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 7925  Solved: 2975[Submit][Status][Discuss] Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完