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;
    }
    
    
    
     
  • 相关阅读:
    python daemon install
    添加 sudoer centos
    CentOS 5安装openssh
    java使用sh或是jsvc来做daemon应该是主流
    Maven JAR Plugin
    The Java™ Tutorials offical学习的好资料哦
    linux下lrzsz安装,SecureCRT上传下载文件工具 寒枫欣叶
    ssh on centos5
    CentOS Linux Install Core Development Tools Automake, Gcc (C/C++), Perl, Python & Debuggers
    Setting an Application's Entry Point
  • 原文地址:https://www.cnblogs.com/BriMon/p/9632610.html
Copyright © 2011-2022 走看看