• HDU


    给定一颗树,每个节点都有忠诚和能力两个参数,随意指定一个节点,要求在它的子树中找一个节点代替它,这个节点要满足能力值大于它,而且是忠诚度最高的那个。

    首先,dfs一下,处理出L[i], R[i]表示dfs序,则R[i] - L[i] + 1 就是当前i这个节点拥有的子孙个数。

    对于一颗树,dfs的时候,访问节点有先后顺序,那么可以用一个struct node List[maxn];表示这课树中访问的先后顺序。

    例如这颗树,我假设是先访问0 --> 3 --> 2 ---> 4 ---> 5 ---> 1

    这样我用一个List数组保存了,同时记录了L[i]和R[i]。那么对于每次询问删除一个节点cur,就是在[L[cur], R[cur]]里面选择了。例如节点2,L[2] = 2, R[2] = 4。那么就变成了区间最值问题。

    分块:块内维护一个数组mx[i]表示当前这个块内能力值 > List[i].ablity的最大忠诚度。想要维护这个,就要开多个数组to_sort[]同样是记录dfs序,但是它要排序,按能力排序,这样可以O(magic)维护完成。

    对于每个查询,不在块内的,暴力,在的,二分出一个 > 当前能力的pos,mx[pos]就是答案。

    复杂度 O (nsqrt(n) + msqrt(n) * logn)

    感觉数据略水,应该用线段树优化掉sqrt(n)

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    const int maxn = 50000 + 20;
    struct edge {
        int u, v, next;
    } e[maxn * 2];
    int first[maxn], R[maxn], L[maxn], mx[maxn];
    int magic;
    struct node {
        int abliatly, loyalty ;
        bool operator < (const node &rhs) const {
            return abliatly < rhs.abliatly;
        }
    } a[maxn], List[maxn], to_sort[maxn];
    int get_id[1000000 + 20];
    int n, num;
    void add (int u, int v)
    {
        ++num;
        e[num].u = u;
        e[num].v = v;
        e[num].next = first[u];
        first[u] = num;
    }
    bool book[maxn];
    int index;
    void dfs (int cur)
    {
        L[cur] = index;
        for (int i = first[cur]; i; i = e[i].next) {
            if (book[e[i].v]) continue;
            book[e[i].v] = 1;
            ++index;
            List[index] = to_sort[index] = a[e[i].v];
            dfs (e[i].v);
        }
        R[cur] = index;
    }
    int find (int begin, int end, int val)
    {
        int t = end;
        if (to_sort[end].abliatly < val) return -1; //不够它大
        if (to_sort[begin].abliatly > val) return mx[begin];//bigger
        while (begin <= end) {
            int mid = (begin + end) >> 1;
            if (to_sort[mid].abliatly > val) end = mid - 1;
            else begin = mid + 1;
        }
        if (begin > t) return -1;
        return mx[begin];
    }
    void work ()
    {
        int Q;
        scanf ("%d%d", &n, &Q);
        magic = (int) sqrt (n * 1.0);
        for (int i = 1; i <= n - 1; ++i) {
            int fa, lo, ab;
            scanf ("%d%d%d", &fa, &lo, &ab);
            add (fa, i);
            a[i].abliatly = ab;
            a[i].loyalty = lo;
            get_id[lo] = i;
        }
        dfs (0); //dfs 构图
        for (int i = 0; i < n; i += magic) {
            int j = i + magic;
            if (j > n) break;
            sort (to_sort + i, to_sort + j);
            mx[j - 1] = to_sort[j - 1].loyalty;
            for (int k = j - 2; k >= i; --k) {
                mx[k] = mx[k + 1] > to_sort[k].loyalty ? mx[k + 1] : to_sort[k].loyalty;
            }
        }
        while (Q--) {
            int id;
            scanf ("%d", &id);
            int val = a[id].abliatly;
            int ans = -inf;
            int begin = L[id], end = R[id];
            for (int i = begin; i <= end;) {
                if (i % magic == 0 && i + magic - 1 <= end) {
                    int t = find (i, i + magic - 1, val);
                    ans = max (ans, t);
                    i += magic;
                } else {
                    if (List[i].abliatly > val && ans < List[i].loyalty) {
                        ans = List[i].loyalty;
                    }
                    ++i;
                }
            }
            printf ("%d
    ", ans < 0 ? -1 : get_id[ans]);
        }
        return ;
    }
    
    int main ()
    {
    #ifdef local
        freopen("data.txt","r",stdin);
    #endif
        int t;
        scanf ("%d", &t);
        a[0].abliatly = -1;
        a[0].loyalty = -1;
        List[0] = to_sort[0] = a[0];
        while (t--) {
            work ();
            memset (first, 0, sizeof first);
            memset (book, 0, sizeof book);
            num = 0;
            index = 0;
            memset (mx, 0, sizeof mx);
        }
        return 0;
    }
    View Code

    线段树预处理优化:

    同样是dfs序处理好,然后按能力从大到小排序,相同的,按id从小到大排序。因为id小的,必然不能成为后面的替身。

    然后首先把线段树初始化为-1,按照能力从大到小去线段树L[id] --- R[id]中查找。

    id就是那个cur,因为它的边是fa -- i的。//正因为这样,才能用这种方法

    为什么呢? 如果它建树的过程不是这样的话,就是不是一直往下建,(这样确保了id小的一定更高级)。这样就没法用id去比较它们的关系了。这个时候,只能分块做了。

    然后就从大到小加入线段树,确保每次查找都是有效值即可

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    const int maxn = 50000 + 20;
    struct edge {
        int u, v;
        int next;
    } e[maxn * 2];
    struct node {
        int loyalty, ability, id;
        bool operator < (const node &rhs) const {
            if (ability != rhs.ability) return ability > rhs.ability;
            else return id < rhs.id;
        }
    } a[maxn];
    int num;
    int first[maxn], L[maxn], R[maxn], get_id[1000000 + 20];
    void add (int u, int v)
    {
        ++num;
        e[num].u = u;
        e[num].v = v;
        e[num].next = first[u];
        first[u] = num;
    }
    bool book[maxn];
    int index;
    void dfs (int cur)
    {
        L[cur] = index;
        for (int i = first[cur]; i; i = e[i].next) {
            if (book[e[i].v] == 0) {
                book[e[i].v] = 1;
                index++;
                dfs (e[i].v);
            }
        }
        R[cur] = index;
    }
    struct data {
        int L,R,mx; //每个节点,都记录一个区间[L,R]。还有记录区间总和
        int mid() {
            return (L + R)/2;
        }
    } SegTree[maxn<<2]; //右移两位,就是*4
    
    void built (int root,int begin,int end)
    {
        SegTree[root].L = begin;
        SegTree[root].R = end;//覆盖区间
        if (begin == end) {
            SegTree[root].mx = -1;
            return ;
        }
        built(root<<1,begin,SegTree[root].mid());
        built(root<<1|1,SegTree[root].mid()+1,end);
        SegTree[root].mx = max(SegTree[root<<1].mx,SegTree[root<<1|1].mx);
        return ;
    }
    void addTT (int root,int pos,int val)
    {
        if (SegTree[root].L == pos && pos == SegTree[root].R) {
            SegTree[root].mx = val;
            return ;
        }
        if (pos <= SegTree[root].mid())     addTT(root<<1,pos,val);
        else if (pos >= SegTree[root].mid()+1)     addTT(root<<1|1,pos,val);
        SegTree[root].mx = max (SegTree[root<<1].mx,SegTree[root<<1|1].mx);
        return ;
    }
    //[begin,end]是要查询的区间,如果所求区间包含线段树覆盖区间,就可以返回
    int find (int root,int begin,int end) //区间查询
    {
        //查询[1,7]的话,左子树区间覆盖了[1,6],也可以直接返回,左子树最大值嘛
        if (begin <= SegTree[root].L && end >= SegTree[root].R)
            return SegTree[root].mx; //覆盖了
        if (end <= SegTree[root].mid()) //完全在左子数
            return find(root<<1,begin,end);
        else if (begin >= SegTree[root].mid() + 1) //完全在右子树
            return find(root<<1|1,begin,end);
        else {
            int Lmax = find(root<<1,begin,end);
            int Rmax = find(root<<1|1,begin,end);
            return max(Lmax,Rmax);
        }
    }
    int ans[maxn];
    void work ()
    {
        int n, Q;
        scanf ("%d%d", &n, &Q);
        for (int i = 1; i <= n - 1; ++i) {
            int fa, lo, ab;
            scanf ("%d%d%d", &fa, &lo, &ab);
            add (fa, i);
            a[i].loyalty = lo;
            a[i].ability = ab;
            a[i].id = i;
            get_id[lo] = i;
        }
        dfs (0);
    //    for (int i = 0; i < n; ++i) {
    //        printf ("%d %d
    ", L[i], R[i]);
    //    }
        built (1, 1, n - 1); //全部设置为-1先
        sort (a + 1, a + n);
    //    for (int i = 1; i <= n - 1; ++i) {
    //        printf ("%d %d
    ", a[i].ability, a[i].loyalty);
    //    }
        for (int i = 1; i <= n - 1; ++i) {
            int id = get_id[a[i].loyalty];
            //printf ("%d****
    ", id);
    //        printf ("%d %d
    ", L[id], R[id]);
            int t = find (1, L[id], R[id]);
            //ans[id] = t;
            if (t == -1) {
                ans[id] = -1;
            } else {
                ans[id] = get_id[t];
            }
            addTT (1, L[id], a[i].loyalty);
        }
        for (int i = 1; i <= Q; ++i) {
            int id;
            scanf ("%d", &id);
            printf ("%d
    ", ans[id]);
        }
        return ;
    }
    
    int main ()
    {
    #ifdef local
        freopen("data.txt","r",stdin);
    #endif
        int t;
        scanf ("%d", &t);
        while (t--) {
            index = 0;
            work ();
            memset (book, 0, sizeof book);
            memset (first, 0, sizeof first);
            index = 0;
            num = 0;
        }
        return 0;
    }
    View Code
  • 相关阅读:
    【学习笔记】《架构整洁之道》(2)
    【学习笔记】《架构整洁之道》(1)
    《漫长的婚约》
    My 2020 work schedule
    canal-clientadapter 数据同步实验
    confluence异常关闭恢复
    nginx 添加第三方nginx_upstream_check_module 模块实现健康状态检测
    keepalived问题阐述及配置
    keepalived+lvs 部署
    lvs基础
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/5827998.html
Copyright © 2020-2023  润新知