1. 程式人生 > >Gym 101915 G(貪心)

Gym 101915 G(貪心)

傳送門

題面:

G. Robots

time limit per test

5.0 s

memory limit per test

256 MB

input

standard input

output

standard output

The Robotics Olympiad teams were competing in a contest.

There was a tree drawn on the floor, consisting of n nodes and n - 1 edges. The nodes are numbered from 1 to n, and each edge has a weight. The tree is rooted at the first node. q

 teams are participating, and each team is given an integer xi. Their robot should start at node 1, and move in the following way until there are no valid moves left: From all the edges between the current node and it's children, go through the edge with the maximum value less than xi. Note that the robot can't move to the parent, only to children.

However, the teams weren't able to program the robots to return to them after the contest, so they had to manually pick them up. Since the tree can be quite large, they need your help to determine where each robot ended it's movement.

Input

The first line contains a single integer T, the number of test cases.

The first line of each test case contains two space-separated integers n and q. (1 ≤ n, q ≤ 105).

The following n - 1 lines contain 3 integers ui, vi, wi. This means that there is an edge connecting nodes ui and vi, with weight wi. (1 ≤ ui, vi ≤ n) (1 ≤ wi ≤ 109). It's guaranteed that all wi are distinct.

The following line contains q integers xi. (1 ≤ xi ≤ 109).

Output

For each test case, print one line with a single number Si, the sum of numbers of nodes where each robot ends.

Example

input 

1
5 7
1 2 3
1 3 4
3 4 9
3 5 7
1 3 4 9 8 7 10

output

21

Note

In the sample test case, the robots end in the following nodes: {1, 1, 2, 5, 5, 3, 4}.

Si = 1+1+2+5+5+3+4 = 21.

Large I/O files. Please consider using fast input/output methods.

題意:

    給出一棵邊權互不相同且根為1的樹,有q個機器人,每個機器人有個權值x,問,從根出發,只能往兒子走,每次會選擇不超過x的最大的邊走下去,如果不存在兒子或者不存在這樣的邊,則停止,問最終會停在哪個點,將所有詢問的答案求和輸出。

題目分析:

    首先,對於每一個結點,你能不能往下走取決於從根到該結點的路徑上的最大值,因此我們首先需要用dfs預處理出來根到每一個結點的最大值max。

    之後我們考慮如下的貪心策略:將所有的邊權以及機器人的權值,均按從大大小進行排序。選取權值最大的機器人從根進行遍歷,直到無法再向下延申。因為邊權按照從大到小排序,因此對於該位置,若有a個機器人的權值大於當前結點的最大值max,則證明這a個機器人均會經過該點,此時我們只需要在此時對答案直接進行更新即可。之後不斷遍歷,直到所有機器人都用完即結束。

程式碼:

#include <bits/stdc++.h>
#define maxn 100005
using namespace std;
struct edge{
    int to,w;
};
vector<edge>vec[maxn<<1];
bool cmp(edge a,edge b){
    return a.w>b.w;
}
void add_edge(int from,int to,int w){
    edge tmp={to,w};
    vec[from].push_back(tmp);
    tmp={from,w};
    vec[to].push_back(tmp);
}
int maxx[maxn],vis[maxn];
void init(int n){
    for(int i=0;i<=n;i++) vec[i].clear();
    memset(vis,0,sizeof(vis));
    memset(maxx,0,sizeof(maxx));
}
void Predfs(int x,int fa){//預處理出每個結點路徑上的最大值
    for(int i=0;i<vec[x].size();i++){
        if(vec[x][i].to==fa) continue;
        maxx[vec[x][i].to]=max(vec[x][i].w,maxx[x]);
        Predfs(vec[x][i].to,x);
    }
}
priority_queue<int>que;
void dfs(int x,long long  &ans){
    vis[x]=1;
    if(que.empty()) return ;
    if(que.top()<=maxx[x]) return ;
    for(int i=0;i<vec[x].size();i++){
        int to=vec[x][i].to;
        if(vis[to]) continue;
        if(vec[x][i].w<que.top()) dfs(to,ans);
    }
    while(que.top()>maxx[x]&&!que.empty()){
        ans+=x;
        que.pop();
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        int n,q;
        scanf("%d%d",&n,&q);
        init(n);
        for(int i=0;i<n-1;i++){
            int from,to,cost;
            scanf("%d%d%d",&from,&to,&cost);
            add_edge(from,to,cost);
        }
        while(q--){
            int num;
            scanf("%d",&num);
            que.push(num);
        }
        for(int i=1;i<=n;i++) sort(vec[i].begin(),vec[i].end(),cmp);
        Predfs(1,-1);
        long long  ans=0;
        dfs(1,ans);
        printf("%lld\n",ans);
    }
}