題目連結
題意
公司裡的每個員工都有一個忠誠度和能力值。
如果把一個員工開除,需要在他的下屬中,找到一個能力值比他高,且忠誠度最大的員工來替代他。
第一行一個整數,表示測試資料組數。
對于每組資料,第一行兩個整數n和m,表示公司的員工數和查詢數。
接下來n-1行,第i行,3個整數,i的上級,忠誠度,能力值。老總的編号為0,所有員工的忠誠度都不一樣。
接下來m行查詢,每行一個整數,表示要開除某個人,輸出替代他的員工編号。如果無法替代,輸出-1.
思路
用DFS序轉為線性存儲,每個人的下級在倆時間戳内。
将每個人按能力值排序。用線段樹維護單點修改,區間查詢的忠誠度最大值。
按能力從大到小,每次先查詢此人的時間戳内忠誠度最大值,如果不存在即-1,存在即表示可被替代,然後單點修改。
由于每個人忠誠度不一樣,可以用map來維護忠誠度與人的編号關系。
有個問題,如果倆人能力值相同,如果先更新兒子節點,那麼查詢會查到父親的值。
是以要先更新父親節點,排序時使能力值相同的人時間戳小的排前面即可。
代碼
#include<bits/stdc++.h>
using namespace std;
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
vector<int> e[50005];
map<int, int> mp;
int tot, ma[200005], ans[50005];
struct Node
{
int lo, ab, l, r;
}data[50005];
bool cmp(Node a, Node b)
{
if(a.ab != b.ab) return a.ab > b.ab;
return a.l < b.l;
}
void init(int n)
{
tot = 0;
mp.clear();
mp[-1] = -1;
for(int i = 0; i <= n; ++i) e[i].clear();
memset(ma,-1,sizeof(ma));
}
void dfs(int u)
{
data[u].l = ++tot;
for(auto v : e[u]) dfs(v);
data[u].r = tot;
}
void updata(int rt, int l, int r, int ql, int lo)
{
if(l == r)
{
ma[rt] = lo;
return;
}
int mid = (l+r)>>1;
if(ql <= mid) updata(lson,ql,lo);
else updata(rson,ql,lo);
ma[rt] = max(ma[rt<<1], ma[rt<<1|1]);
}
int query(int rt, int l, int r, int ql, int qr)
{
if(ql <= l && r <= qr) return ma[rt];
int mid = (l+r)>>1, tmp = -1;
if(ql <= mid) tmp = max(tmp, query(lson,ql,qr));
if(mid < qr) tmp = max(tmp, query(rson,ql,qr));
return tmp;
}
int main()
{
int t;
for(scanf("%d",&t); t; --t)
{
int n, m, u;
scanf("%d%d",&n,&m);
init(n);
for(int i = 1; i < n; ++i)
{
scanf("%d%d%d",&u,&data[i].lo,&data[i].ab);
mp[data[i].lo] = i;
e[u].push_back(i);
}
dfs(0);
sort(data+1,data+n,cmp);
for(int i = 1; i < n; ++i)
{
ans[mp[data[i].lo]] = mp[query(1,1,tot,data[i].l,data[i].r)];
updata(1,1,tot,data[i].l,data[i].lo);
}
for(; m--; printf("%d\n",ans[u])) scanf("%d",&u);
}
return 0;
}