Codeforces 1213G Path Queries

本文介绍了一种解决特定CF题目(涉及无根树与边权)的方法,通过将边按权值排序,并利用并查集数据结构来高效计算路径最大值不超过给定阈值的点对数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

cf题面

中文题面

给一棵无根树,每条边有边权。然后q个询问,每次询问给个w,求树上有多少对点之间的路径上的最大值小于等于w。

解题思路

离线。先把所有边按照边长升序排序,再把所有询问按照w升序排序。

之后从小到大处理每个询问。对于一个询问,首先由于询问已经排好序了,所以前一个答案是之前加的边对于答案的贡献,我们就先把上一个询问的答案直接复制过来,之后把小于等于这个询问的w的所有边加入到树上,然后并查集更新答案:每加一条边,对答案产生的贡献是“这条边两端的连通块”大小之积。

之后恢复顺序,输出,没了。

虚拟赛过程中看见这题的时候,想不到用并查集,而是想着深搜(类似这个),对于一条边,讨论它下方的子树和上方树的其他部分的情况,但上方没想出来怎么处理,因为可能上方存在权值更大的边,不能一整个乘下去……然后想到点分治树分治啥的,全是xjb想……去看了这题的标签,dsu(并查集)、分治、排序。开始不知道啥是dsu,去百度找到了个dsu on tree,点进去发现时启发式合并,和这个没啥关系……

源代码

#include<cstdio>
#include<algorithm>
 
const int MAXN=2e5+5;
int n,m;
 
struct Que{
    int id,w;
    long long ans;
}q[MAXN];
bool cmp1(Que & a,Que & b){return a.w<b.w;}
bool cmp2(Que & a,Que & b){return a.id<b.id;}
struct Edge{
    int u,v,w;
    bool operator < (const Edge & x)const{
        return w<x.w;
    }
}e[MAXN];
 
int fa[MAXN],sz[MAXN];
int find(int x)
{
    return fa[x]=fa[x]==x?x:find(fa[x]);
}
void uni(int x,int y)
{
    x=find(x);
    y=find(y);
    fa[x]=y;
    sz[x]+=sz[y];
    sz[y]=sz[x];
}
 
int main()
{
//  freopen("test.in","r",stdin);
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
    }
    for(int i=0;i<m;i++)
    {
        scanf("%d",&q[i].w);
        q[i].id=i;
        q[i].ans=0;
    }
    std::sort(e+1,e+n);
    std::sort(q,q+m,cmp1);
    for(int i=1;i<=n;i++) fa[i]=i,sz[i]=1;
    for(int i=0,pos=1;i<m;i++)
    {
        q[i].ans=q[i-1].ans;
        while(pos<n&&e[pos].w<=q[i].w)
        {
            int u=e[pos].u,v=e[pos].v;
            q[i].ans+=1LL*sz[find(u)]*sz[find(v)];
            uni(u,v);
            pos++;
        }
    }
    std::sort(q,q+m,cmp2);
    for(int i=0;i<m;i++) printf("%lld ",q[i].ans);
    return 0;
}

转载于:https://www.cnblogs.com/wawcac-blog/p/11466151.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值