codeforces 1213G Path Queries(补题)

https://codeforces.com/problemset/problem/1213/G

题意: 给你一棵树 然后树的边有权值 每次询问树的路径中最大的权值不超过k的路径数量

思路:如果我们一开始就把树建好 然后每次都去dfs的话 那么肯定是会超时的 那么就考虑将询问离线!!!(常用操作) 对于每一个离线的询问的值W 把小于W的边都加入进来 这个时候是用并查集维护联通快的个数 然后答案就是每个联通快中初始点的个数n * (n - 1) / 2;初始值为0 每次加边改变答案
当两个联通快合并时 需要减去原先两个联通块的贡献 然后在加上新合并联通块的贡献 然后记录答案

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxn = 3e5 + 10;
int pre[maxn];
ll sum[maxn],t_ans[maxn];
struct node{
    int u;
    int v;
    ll w;
}edge[maxn];
struct qqq{
    ll val;
    int pos;
}query[maxn];
int find(int x)
{
    return pre[x] == x ? x : pre[x] = find(pre[x]);
}
bool cmp(node x,node y)
{
    return x.w < y.w;
}
bool cmp1(qqq x,qqq y)
{
    return x.val < y.val;

}
int main()
{
    int n,q;
    scanf("%d%d",&n,&q);
    for(int i = 1; i <= n - 1; i++)
    {
        scanf("%d%d%I64d",&edge[i].u,&edge[i].v,&edge[i].w);
    }
    sort(edge + 1,edge +  n, cmp);
    for(int i = 1; i <= q; i++)
    {
        scanf("%I64d",&query[i].val);
        query[i].pos = i;
    }
    sort(query + 1,query + 1 + q, cmp1); // 询问离线
    for(int i = 1; i <= n; i++)
    {
        pre[i] = i;
        sum[i] = 1;
    }
    int len = 1;
    ll temp = 0;
    for(int i = 1; i <= q; i++)
    {
        //cout<<query[i].val<<endl;
        while(query[i].val >= edge[len].w && len <= n - 1)
        {
            //cout<<edge[len].w<<endl;
            int x = find(edge[len].v), y = find(edge[len].u);
            if(x != y) // 更新答案
            {
                temp -= (sum[x] * (sum[x] - 1) / 2);
                temp -= (sum[y] * (sum[y] - 1) / 2);
                sum[y] += sum[x];pre[x] = y;
                temp += (sum[y] * (sum[y] - 1) / 2);
            }
            len++;
        }
        t_ans[query[i].pos] = temp;
    }
    for(int i = 1; i <= q; i++)
    {
        cout<<t_ans[i]<<" ";
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值