zoukankan      html  css  js  c++  java
  • HDU 4366 Successor

    题意:给你一棵树,求树中某节点子树中能力值大于它且忠诚度最高的那个。

    在第一次看到这个问题是,我有一个疑问:

    解决这个问题有两个关键点:


    1.树形结构到线性结构的转换

    原因:员工关系整棵树是一棵结构不确定的树,员工编号不一定连续,对于查询其符合条件的下属有很大困难(只能暴力)。而编号之后可以将子树映射到编号连续的一段区间,这时就可以用线段树快速查询最值。
    做法:用邻接表保存树,从根开始DFS,记录每棵子树的起始端点和终止端点。

    2.对能力值从大到小进行排序,按能力值从大到小的顺序加入线段树,能力值相同时,编号小的在前面。

    原因:因为每次要查找能力值大于该人且忠诚度最高的那个下属,所以当该点插入线段树时,线段树中已有的节点全部是能力值高于他的人,所以只需要在这群人中,属于其下属的子树区间内查询一下忠诚度的最值即可。
    做法:线段树节点用于保存最高忠诚度。细节见代码。

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <cstdlib>
      4 #include <algorithm>
      5 
      6 #define lson l, m, rt << 1
      7 #define rson m + 1, r, rt << 1 | 1
      8 
      9 using namespace std;
     10 
     11 const int MAXN = 50002;
     12 
     13 struct staff      //员工节点
     14 {
     15     int superior;
     16     int ability;
     17     int loyalty;
     18 };
     19 
     20 struct node       //邻接表保存树
     21 {
     22     int v;
     23     int next;
     24 };
     25 
     26 struct subTree    //存储子树的起始编号和终止编号
     27 {
     28     int st;
     29     int ed;
     30 };
     31 
     32 int N, Q;
     33 int EdgeN, dfs_clock;
     34 //邻接表保存树
     35 node D[MAXN];
     36 int head[MAXN];
     37 
     38 int ans[MAXN];     //存储答案
     39 
     40 staff F[MAXN];
     41 subTree sub[MAXN];   //存储编号为i的员工,其下属的起始编号和终止编号
     42 
     43 int maxi[ MAXN << 2 ];   //线段树,存储忠诚度的最大值
     44 
     45 int vis[ 1000010 ];      //忠诚度→编号映射
     46 
     47 bool cmp( staff a, staff b )
     48 {
     49     return a.ability > b.ability;
     50 }
     51 
     52 void AddEdge( int u, int v )    //头插法加点
     53 {
     54     D[EdgeN].v = v;
     55     D[EdgeN].next = head[u];
     56     head[u] = EdgeN++;
     57     return;
     58 }
     59 
     60 void DFS( int cur )             //DFS遍历,记录其子树的起始编号和终止编号
     61 {
     62     sub[cur].st = dfs_clock++;
     63     for ( int i = head[cur]; i != -1; i = D[i].next )
     64         DFS( D[i].v );
     65     sub[cur].ed = dfs_clock;
     66 }
     67 
     68 void init()                     //初始化
     69 {
     70     EdgeN = 1;
     71     memset( head, -1, sizeof(head) );
     72     memset( maxi, -1, sizeof(maxi) );
     73     dfs_clock = 1;
     74     return;
     75 }
     76 
     77 int query( int L, int R, int l, int r, int rt )   //区间查最值
     78 {
     79     if ( L <= l && r <= R ) return maxi[rt];
     80 
     81     int m = ( l + r ) >> 1;
     82 
     83     int ret = -1;
     84     if ( L <= m ) ret = max( ret, query( L, R, lson ) );
     85     if ( R > m )  ret = max( ret, query( L, R, rson ) );
     86 
     87     return ret;
     88 }
     89 
     90 void PushUp( int rt )
     91 {
     92     maxi[rt] = max( maxi[ rt << 1 ], maxi[ rt << 1 | 1 ] );
     93     return;
     94 }
     95 
     96 void update( int id, int val, int l, int r, int rt )   //节点加入线段树
     97 {
     98     if ( l == id && r == id )
     99     {
    100         maxi[rt] = val;
    101         return;
    102     }
    103 
    104     int m = ( l + r ) >> 1;
    105     if ( id <= m ) update( id, val, lson );
    106     else update( id, val, rson );
    107 
    108     PushUp( rt );
    109     return;
    110 }
    111 
    112 int main()
    113 {
    114     int T;
    115     scanf( "%d", &T );
    116     while ( T-- )
    117     {
    118         init();
    119 
    120         scanf( "%d%d", &N, &Q );
    121         for ( int i = 1; i < N; ++i )
    122         {
    123             int a, aby, loy;
    124             scanf( "%d%d%d", &a, &loy, &aby );
    125             AddEdge( a, i );
    126             F[i].ability = aby;
    127             F[i].loyalty = loy;
    128             F[i].superior = a;
    129             vis[loy] = i;
    130         }
    131 
    132         DFS( 0 );  //根节点编号为0
    133 
    134         sort( F + 1, F + N, cmp );  //按能力值从大到小排序
    135 
    136         int j;
    137         for ( int i = 1; i < N; i = j )
    138         {
    139             j = i;
    140             while ( j < N && F[i].ability == F[j].ability )
    141             {
    142                 int id = vis[ F[j].loyalty ];
    143                 int tp = -1;
    144                 if ( sub[id].st + 1 <= sub[id].ed - 1 )
    145                     tp = query( sub[id].st + 1, sub[id].ed - 1, 1, dfs_clock - 1, 1 );
    146                 if ( tp == -1 ) ans[id] = -1;
    147                 else ans[id] = vis[tp];
    148                 ++j;
    149             }
    150 
    151             j = i;
    152             while ( j < N && F[i].ability == F[j].ability )
    153             {
    154                 int id = vis[ F[j].loyalty ];
    155                 update( sub[id].st, F[j].loyalty, 1, dfs_clock - 1, 1 );
    156                 ++j;
    157             }
    158         }
    159 
    160         while ( Q-- )
    161         {
    162             int a;
    163             scanf( "%d", &a );
    164             printf( "%d\n", ans[a] );
    165         }
    166     }
    167     return 0;
    168 }
  • 相关阅读:
    mysql在第一次查询的时候很慢,第二次查询就比较快的原因?
    mysql的递归(使用函数)
    什么样的男人才是女人眼中最帅的男人
    面试题总结
    java的重载总结
    arduino读取GPIO数据
    electron+react项目改为typescript
    百度AI训练营笔记
    python读取文件出现ufeff问题
    大端小端
  • 原文地址:https://www.cnblogs.com/GBRgbr/p/3061092.html
Copyright © 2011-2022 走看看