Successor (HDU-4366)分块(单点更新,区间查询最值,预处理,DFS序)

Sean owns a company and he is the BOSS.The other Staff has one Superior.every staff has a loyalty and ability.Some times Sean will fire one staff.Then one of the fired man’s Subordinates will replace him whose ability is higher than him and has the highest loyalty for company.Sean want to know who will replace the fired man.

Input

In the first line a number T indicate the number of test cases. Then for each case the first line contain 2 numbers n,m (2<=n,m<=50000),indicate the company has n person include Sean ,m is the times of Sean’s query.Staffs are numbered from 1 to n-1,Sean’s number is 0.Follow n-1 lines,the i-th(1<=i<=n-1) line contains 3 integers a,b,c(0<=a<=n-1,0<=b,c<=1000000),indicate the i-th staff’s superior Serial number,i-th staff’s loyalty and ability.Every staff ‘s Serial number is bigger than his superior,Each staff has different loyalty.then follows m lines of queries.Each line only a number indicate the Serial number of whom should be fired.

Output

For every query print a number:the Serial number of whom would replace the losing job man,If there has no one to replace him,print -1.

Sample Input

1
3 2
0 100 99
1 101 100
1
2

Sample Output

2
-1

题意: 给你一棵树,每个结点有两个属性值:1:能力值  2:忠诚度;然后m个询问,每次询问一个整数u,求u的子树中能力值大于u的且忠诚度最大的点的编号。

思路:思路的话,借鉴一下dalao的博客。

首先,这个题目要求找的是子树中忠诚值最大的。这个倒是可以用线段树去维护。因为一个树的线性序列的子树都在一个连续序列(有个进入这棵子树的时间戳和出去的时间戳)中,所以只要像往常一样去维护一棵普通的求最大值的线段树即可。 题目还要求能力要比根强。对于这个,我们的策略是先在线段树里面插入能力强的,再插入能力弱的。那么,前面的在查询的时候就不会查询到能力比自己弱的了。(能力一样的应该一起插入。)

实现:

         预处理:1.同时记录一个人的能力,忠诚度和编号。由于用线段树维护的是loyalty,那么最后询问出来的肯定也是loyalty的值,所以用map对loyalty和编号id进行一一映射(loyalty唯一,所以才能有一一映射的关系)。   2.将一棵树映射为一个线性序列,分别用两个数组去记录每个节点进去的时间和出去的时间。用深度优先搜索,有那么一点像线序遍历。3.按照能力值进行排序。
         4.按能力值从大到小一一批量处理,能力相同的为同一批。将答案存入一个数组当中。最后以O(1)的复杂度进行询问。

AC代码:

#include <bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef long long ll;
const int maxx=50010;
const int inf=0x3f3f3f3f;
using namespace std;
struct node
{
    int id;
    int loty;
    int abty;
    bool operator<(const node&cmp)const
    {
        return abty>cmp.abty;
    }
} emp[maxx];
int Max[maxx<<2],t,n,m,ans[maxx],L[maxx],R[maxx],head[maxx],tot,ed;
map<int,int>mp;
struct Edge
{
    int v,next;
} edge[maxx];
void add(int u,int v)
{
    edge[ed].v=v;
    edge[ed].next=head[u];
    head[u]=ed++;
}
void dfs(int rt)
{
    L[rt]=tot++;
    for(int i=head[rt]; i!=-1; i=edge[i].next)
    {
        dfs(edge[i].v);
    }
    R[rt]=tot;
}
int query(int L,int R,int l,int r,int rt)
{
    if(L>R)
        return -1;
    if(L<=l && r<=R)
    {
        return Max[rt];
    }
    int m=(l+r)>>1;
    int ll=-1,rr=-1;
    if(L<=m)
        ll=query(L,R,lson);
    if(R>m)
        rr=query(L,R,rson);
    return max(ll,rr);
}
void update(int &pos,int &val,int l,int r,int rt)
{
    if(l==r)
    {
        Max[rt]=val;
        return ;
    }
    int m=(l+r)>>1;
    if(pos<=m)
        update(pos,val,lson);
    else
        update(pos,val,rson);
    Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);
}
void init()
{
    mp.clear();
    mp[-1]=-1;
    tot=ed=0;
    memset(L,0,sizeof(L));
    memset(R,0,sizeof(R));
    memset(ans,-1,sizeof(ans));
    memset(head,-1,sizeof(head));
    memset(Max,-1,sizeof(Max));
    for(int i=1,fa; i<n; i++)
    {
        scanf("%d%d%d",&fa,&emp[i].loty,&emp[i].abty);
        add(fa,i);
        mp[emp[i].loty]=i;
        emp[i].id=i;
    }
    dfs(0);
    sort(emp+1,emp+n);
}
void solve()
{
    int fired;
    while(m--)
    {
        scanf("%d",&fired);
        printf("%d\n",ans[fired]);
    }
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        init();
        for(int i=1,j; i<n; i=j)
        {
            j=i;
            while(j<n && emp[j].abty==emp[i].abty)
            {
                int id=emp[j].id;
                int lo=query(L[id]+1,R[id]-1,0,tot-1,1);
                ans[id]=mp[lo];
                j++;
            }
            j=i;
            while(j<n && emp[j].abty==emp[i].abty)
            {
                int id=emp[j].id;
                update(L[id],emp[j].loty,0,tot-1,1);
                j++;
            }
        }
        solve();
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值