Codeforce 1213G Path query 并查集

You are given a weighted tree consisting of nn vertices. Recall that a tree is a connected graph without cycles. Vertices uiui and vivi are connected by an edge with weight wiwi.

You are given mm queries. The ii-th query is given as an integer qiqi. In this query you need to calculate the number of pairs of vertices (u,v)(u,v) (u<vu<v) such that the maximum weight of an edge on a simple path between uu and vv doesn't exceed qiqi.

Input

The first line of the input contains two integers nn and mm (1≤n,m≤2⋅1051≤n,m≤2⋅105) — the number of vertices in the tree and the number of queries.

Each of the next n−1n−1 lines describes an edge of the tree. Edge ii is denoted by three integers uiui, vivi and wiwi — the labels of vertices it connects (1≤ui,vi≤n1≤ui,vi≤n, ui≠viui≠vi) and the weight of the edge (1≤wi≤2⋅1051≤wi≤2⋅105). It is guaranteed that the given edges form a tree.

The last line of the input contains mm integers q1,q2,…,qmq1,q2,…,qm (1≤qi≤2⋅1051≤qi≤2⋅105), where qiqi is the maximum weight of an edge in the ii-th query.

Output

Print mm integers — the answers to the queries. The ii-th value should be equal to the number of pairs of vertices (u,v)(u,v) (u<vu<v) such that the maximum weight of an edge on a simple path between uu and vv doesn't exceed qiqi.

Queries are numbered from 11 to mm in the order of the input.

Examples

Input

7 5
1 2 1
3 2 3
2 4 1
4 5 2
5 7 4
3 6 2
5 2 3 4 1

Output

21 7 15 21 3 

Input

1 2
1 2

Output

0 0 

Input

3 3
1 2 1
2 3 2
1 3 2

Output

1 3 3 

Note

The picture shows the tree from the first example: 

题目大意:给你一颗带权树,每次询问一个qi,问有多少条路径满足该路径上的最大值小于等于qi

题目思路:

我们只需要考虑,路径不超过i的边有多少条

我们从小到大将边权排序,一次一次的往图中加边,我们考虑当新加的一条边时,这条边会连接两个联通块,这时会增加一部分贡献,这部分贡献就是sum[a]*sum[b](sum数组表示当前联通块的大小,也就是节点数的多少).之后考虑两个情况:

第一种当前加的边权值相同:

首先理解:毎向一个联通块b添加一个点a,路径条数就会增加 sum[a]*sum[b]

假设当前图无边,加进1 2 1 ,所以权值 0+=1*1 //以下这所有算式 表示sum[a]*sum[b] 然后更新让2->1 sum[1]+=sum[2] sum[2]=0,sum[1]为根

再来一条边 2 3 1 此时 2为1  1+=2*1=3  然后更新 3->2->1  sum[1]继续更新

以上为第一种情况

第二种当不同时,因为没有考虑到权值全为1的连通块中的数目,所以我们要加上为1的:

此时边权为1的边完了,那么为1的联通块中数目就是3,再来一条边 3 4 2 此时 sum[3]=3  所以 合并之后 0+=3*1=3

边权为2的是1(但这是混合图),所以要加上为1的联通块内部的路径数PS:(这一部分就是前缀和),仔细体会一下

AC:

#include <bits/stdc++.h>
/*#include<stdio.h>
#include<vector>
#include<queue>
#include<string.h>*/
#pragma GCC optimize(2)
typedef long long ll;
typedef unsigned long long ull;
const int mod=1000;
const int maxn=1e6+5;
const ll INF=10000000000000005;
using namespace std;
ll n,m,p;
ll pre[maxn];
ll sum[maxn];
struct node{
    int s,e;ll w;
    bool friend operator<(node a,node b)
    {
        return a.w<b.w;
    }
}edge[maxn];
struct Save{
    ll  w;int id;
    bool friend operator<(Save a,Save b)
    {
        return a.w<b.w;
    }
}save[maxn];
ll res[maxn];
int Find(int x)
{
    return pre[x]==x?x:pre[x]=Find(pre[x]);
}
int main()
{
    ll maxl=-1;
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n-1;i++) scanf("%lld%lld%lld",&edge[i].s,&edge[i].e,&edge[i].w);
    for(int i=1;i<=m;i++){
        scanf("%d",&save[i].w);
        save[i].id=i;
        maxl=max(maxl,save[i].w);
    }
    sort(edge+1,edge+n);
    sort(save+1,save+1+m);
    for(int i=1;i<=n;i++) pre[i]=i,sum[i]=1;
    for(int i=1;i<=n-1;i++)
    {
        int dx=Find(edge[i].s),dy=Find(edge[i].e);
        if(dx!=dy)
        {
            //printf("dx:%d  dy:%d  sumx:%d  sumy:%d   w:%d\n",dx,dy,sum[dx],sum[dy],edge[i].w);
            ll temp=sum[dx]*sum[dy];
            sum[dx]+=sum[dy];sum[dy]=0;
            pre[dy]=dx;
            res[edge[i].w]+=temp;
        }
    }
    int s=1;
    ll sum=0;
    for(int i=1;i<=maxl;i++)
        res[i]=res[i-1]+res[i];
    for(int i=1;i<=m;i++)
    {
        while(s<save[i].w) s++;
        pre[save[i].id]=res[s];
    }
    for(int i=1;i<=m;i++)
        printf("%lld ",pre[i]);
}
/***
样例测试空间:
6
5
1 2
2 3
3 1
3 5
2 6
***/

总结:

这次一定要记住这个思想了,询问路径数时,可以一个点一个点的往里加,每次添加一个点,路径数就是+联通块内点的个数;

全部评论

相关推荐

不愿透露姓名的神秘牛友
11-26 18:54
说等下个版本吧的发呆爱好者很贪睡:佬最后去了哪家呀
点赞 评论 收藏
分享
冲芭芭拉鸭:你这图还挺新,偷了。
投递美团等公司10个岗位
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务