• bzoj2282 [SDOI2011]消防


    题目

      bzoj2282

    题解

      首先吐槽一发题意

      选择的路径可以不包含边???

      只包含一个节点也算路径???

      惹不起 惹不起

      然后我们就可以发现,离任意一点最远的点必然是直径的端点,所以所选路径至少有一点在树的直径上

      此时答案即为较远端点到当前点的距离

      剩下的点若不在直径上,无法更新直径端点到所选路径的距离,答案不变

      所以整条路径都在直径上答案是最优的

      于是二分

      (树的直径两遍bfs求得)

    代码

      

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 300005;
    const int M = 2 * N;
    
    inline int read()
    {
    	int x = 0, f = 1; char ch = getchar();
    	while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
    	while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
    	return x * f;
    }
    
    int n, len;
    
    struct node
    {
    	int fr, to, w, nt;
    	node(int ff = 0, int tt = 0, int ww = 0, int nn = 0) {fr = ff; to = tt; w = ww; nt = nn;}
    }E[M];
    int num, p[N];
    
    void add(int x, int y, int z) {E[++num] = node(x, y, z, p[x]); p[x] = num;}
    
    int dis[N], from[N]; queue<int> q; bool mark[N];
    void bfs(int s)
    {
    	memset(dis, -1, sizeof(dis));
    	q.push(s); dis[s] = 0;
    	while(!q.empty())
    	{
    		int x = q.front(); q.pop();
    		for(int e = p[x]; e; e = E[e].nt)
    		{
    			int k = E[e].to;
    			if(dis[k] != -1) continue;
    			from[k] = x; q.push(k);
    			if(mark[E[e].to]) dis[k] = dis[x];
    			else dis[k] = dis[x] + E[e].w;
    		}
    	}
    }
    
    int dia, st[N];//st[i]记录i到s的距离
    void get_dia()
    {
    	int s = 0, t = 0;
    	bfs(1);
    	for(int i = 1; i <= n; i++) if(dis[i] > dis[s]) s = i;
    	bfs(s);
    	for(int i = 1; i <= n; i++) if(dis[i] > dis[t]) t = i;
    	dia = dis[t];
    	st[++st[0]] = dis[t]; mark[t] = true;
    	while(t != s)
    	{
    		st[++st[0]] = dis[from[t]];
    		t = from[t]; mark[t] = true;
    	}
    	bfs(s);
    }
    
    bool check(int mid)
    {
    	int l = 1, r = st[0];
    	while(st[1] - st[l + 1] <= mid && l <= st[0]) l++;
    	while(st[r - 1] <= mid && r >= 1) r--;
    	return st[l] - st[r] <= len;
    }
    
    int main()
    {
    	n = read(); len = read();
    	for(int i =  1; i < n; i++)
    	{
    		int x = read(), y = read(), z = read();
    		add(x, y, z); add(y, x, z);
    	}
    	get_dia();
    	int l = 0, r = dia, ans = 0;
    	for(int i = 1; i <= n; i++) ans = max(ans, dis[i]);
    	if(len < dia)
    		while(l <= r)
    		{
    			int mid = (l + r) >> 1;
    			if(check(mid)) {ans = mid; r = mid - 1;}
    			else l = mid + 1;
    		}
    	printf("%d", ans);
    	return 0;
    }
    
  • 相关阅读:
    Docker Registry 管理镜像
    Dockerfile 构建镜像
    制作docker镜像
    docker 使用及基本命令
    centos7 安装 docker
    spring-boot-devtools 热部署
    mysql库复制
    windows下安装和设置gradle
    springboot项目搭建
    下载和安装
  • 原文地址:https://www.cnblogs.com/XYZinc/p/9168998.html
Copyright © 2020-2023  润新知