zoukankan      html  css  js  c++  java
  • [牛客网NOIP赛前集训营-提高组(第一场)]C.保护

    链接:https://www.nowcoder.com/acm/contest/172/C
    来源:牛客网

    题目描述

    C国有n个城市,城市间通过一个树形结构形成一个连通图。城市编号为1到n,其中1号城市为首都。国家有m支军队,分别守卫一条路径的城市。具体来说,对于军队i,他守卫的城市区域可以由一对二元组(xi,yi)代表。表示对于所有在xi到yi的最短路径上的城市,军队i都会守卫他们。
    现在有q个重要人物。对于一个重要人物j,他要从他的辖区vj出发,去到首都。出于某些原因,他希望找到一个离首都最近的,且在vj到首都路径上的城市uj,使得至少有kj支军队,能够全程保护他从vj到uj上所经过的所有城市。换句话说,至少有ki支军队,满足在树上,xi到yi的路径能完全覆盖掉vj到uj的路径。

    输入描述:

    第一行输入两个数n,m。
    接下来n-1行,每行两个整数u,v,表示存在一条从城市u到城市v的道路。
    接下来m行,每行两个整数x,y。描述一个军队的守卫区域。
    接下来一行一个整数q。
    接下来q行,每行两个整数vj,kj

    输出描述:

    对于每次询问,输出从v
    j
    到u
    j
    最少需要经过多少条边。假如不存在这样的u
    j
    ,则输出0。
    示例1

    输入

    复制
    8 8
    7 1
    1 3
    3 4
    4 6
    6 2
    4 5
    7 8
    7 2
    7 1
    7 1
    7 5
    1 1
    1 3
    1 6
    5 1
    8
    5 1
    2 1
    2 1
    4 2
    3 2
    4 2
    1 1
    4 1
    

    输出

    复制
    3
    4
    4
    2
    1
    2
    0
    2
    

    备注:

    20%: n,m,q <= 300
    40%: n,m,q <= 2000
    60%: n,m,q <= 50000
    100%: n,m,q <= 200000





    题目给你一堆点对(X,Y),并且让你求出对于另外的给定点u,保证有k条路径完全覆盖(u,v)的v的最小深度。
    我们考虑把(x,y)分为(x,p), (y,p), p为x和y的lca。
    那么(u,v)被(x,y)覆盖其实就是(u,v)被(x,p)或者(y,p)覆盖。
    这里我们只考虑被(x,p)覆盖。
    那么肯定是x在u的子树中,p在v的子树之外。
    我们对于每一个节点开一棵权值线段树,在x的线段树上的dep[p]位置+1,代表(x,p)有一条路径。
    那么我们要(u,v)被(x,p)覆盖,只需要查询u的子树中的线段树是否有<=dep[v]的标记。
    如果有那么就成立。
    我们要找(u,v)被大于等于k条路径完全覆盖,很容易的想到区间第k小,我们只要在u的子树中的线段树上查询最小的k的存在标记的位置,就是v的深度。
    此题完美解决。
    (我太菜了考试的时候没想出来)。
    所以重复一遍步骤 :
    1.在每个节点开一棵权值线段树,然后对于每个(x,y)在x,y的线段树上分别在dep[lca(x,y)]的位置上+1.
    2.dfs一遍合并一个节点儿子的所有子树的线段树。
    3.对于每个询问,查询u的线段树中的第k小的位置记为e,答案就是dep[p]-e。




    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    using namespace std;
    #define reg register 
    inline int read() {
        int res = 0;char ch=getchar();bool fu=0;
        while(!isdigit(ch)) {if(ch=='-')fu=1;ch=getchar();}
        while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48), ch=getchar();
        return fu?-res:res;
    }
    #define N 200005
    int n, m;
    struct edge {
        int nxt, to;
    }ed[N*2];
    int head[N], cnt;
    inline void add(int x, int y) {
        ed[++cnt] = (edge){head[x], y};
        head[x] = cnt;
    }
    
    int dep[N];
    int ff[N][20];
    inline void bfs()
    {
        dep[1] = 1;
        dep[0] = -1;
        queue <int> q;
        q.push(1);
        while(!q.empty())
        {
            int x = q.front();q.pop();
            for (reg int i = head[x] ; i ; i = ed[i].nxt)
            {
                int to = ed[i].to;
                if (dep[to]) continue;
                dep[to] = dep[x] + 1;
                ff[to][0] = x;
                for (reg int j = 1 ; j <= 19 ; j ++)
                    ff[to][j] = ff[ff[to][j-1]][j-1];
                q.push(to);
            }
        }
    }
    
    inline int lca(int x, int y) 
    {
        if (dep[x] < dep[y]) swap(x, y);
        for (reg int i = 19 ; i >= 0 ; i --)
            if (dep[ff[x][i]] >= dep[y]) x = ff[x][i];
        if (x == y) return x;
        for (reg int i = 19 ; i >= 0 ; i --)
            if (ff[x][i] != ff[y][i]) x = ff[x][i], y = ff[y][i];
        return ff[x][0];
    }
    
    int ls[N*105], rs[N*105], tr[N*105], tot;
    int root[N*105];
    
    int Insert(int l, int r, int o, int p)
    {
        if (!o) o = ++tot;
        tr[o]++;
        if (l == r) return o;
        int mid = l + r >> 1;
        if (p <= mid) ls[o] = Insert(l, mid, ls[o], p);
        else rs[o] = Insert(mid + 1, r, rs[o], p);
        return o;
    }
    
    int Merge(int l, int r, int a, int b)
    {
        if (a * b == 0) return a + b;
        int node = ++tot;
        tr[node] = tr[a] + tr[b];
        if (l == r) return node;
        int mid = l + r >> 1;
        ls[node] = Merge(l, mid, ls[a], ls[b]);
        rs[node] = Merge(mid + 1, r, rs[a], rs[b]);
        return node;
    }
    
    void dfs(int x, int fa) 
    {
        for (reg int i = head[x] ; i ; i = ed[i].nxt)
        {
            int to = ed[i].to;
            if (to == fa) continue;
            dfs(to, x);
            root[x] = Merge(1, n, root[x], root[to]);
        }
    }
    
    int K_th(int l, int r, int o, int k)
    {
        if (tr[o] < k) return 1e9;
        if (l == r) return l;
        int mid = l + r >> 1;
        if (tr[ls[o]] >= k) return K_th(l, mid, ls[o], k);
        else return K_th(mid + 1, r, rs[o], k - tr[ls[o]]);
    }
    
    int main()
    {
        n = read(), m = read();
        for (reg int i = 1 ; i < n ; i ++)
        {
            int x = read(), y = read();
            add(x, y), add(y, x);
        }
        bfs();
        for (reg int i = 1 ; i <= m ; i ++)
        {
            int x = read(), y = read();
            int l = lca(x, y);
            root[x] = Insert(1, n, root[x], dep[l]);
            root[y] = Insert(1, n, root[y], dep[l]);
        }
        dfs(1, 0);
        int q = read();
        while(q--)
        {
            int x = read(), k = read();
            printf("%d
    ", max(0, dep[x] - K_th(1, n, root[x], k)));
        }
        return 0;
    }
    
    
    
     
  • 相关阅读:
    【反射】Java反射机制
    Composer教程之常用命令
    Composer教程之基础用法
    Composer教程之初识Composer
    Composer 的结构详解
    现代 PHP 新特性系列(七) —— 内置的 HTTP 服务器
    现代 PHP 新特性系列(一) —— 命名空间
    现代 PHP 新特性系列(二) —— 善用接口
    现代 PHP 新特性系列(三) —— Trait 概览
    现代 PHP 新特性系列(四) —— 生成器的创建和使用
  • 原文地址:https://www.cnblogs.com/BriMon/p/9632610.html
Copyright © 2011-2022 走看看