zoukankan      html  css  js  c++  java
  • CodeForces

    题目:https://vjudge.net/contest/323699#problem/A

    题意:给你一棵树,然后有m个查询,每次查询问一条路径最大边小于给定查询的数量

    思路:首先我们看到,我们其实可以计算出每个边权小于查询的所有连通块,然后sum+C(n,2),对每个连通块都加上值,然后就是答案了,但是这里注意查询数很多,我们肯定不能O(n)遍历每个查询,但是思路肯定是计算联通块里组合数的数量,怎么处理呢,我们注意到,他这个边权是的值的大小和我的连通块的有关,我们是否可以利用之前求出来的值呢,答案是可以的,我们可以对查询排序,先求值小的,然后到后面查询的时候用之前的连通块继续延伸,总的所有查询的复杂度我们也只是遍历了一遍树,但是我们dfs不好去处理,这里我们怎么弄呢,连通块的算法就那么几个,dfs,并查集,tarjan,我们可以排除dfs和tarjan,那么我们就肯定是用并查集了,我们对边权也进行排序,然后我们就可以利用每个边进行联通块的合并,然后贡献怎么计算呢,我们会发现A连通块和B连通块,然后A连通块的路径对已经算完了,B连通块的路径对算完了,然后现在要求的一个点在A连通块,一个点在Bl连通块,贡献就加上A.size*B.size

    #include<bits/stdc++.h>
    #define maxn 200005
    #define mod 1000000007
    using namespace std;
    typedef long long ll;
    struct sss{
        ll x,y,z;
    }a[maxn];
    struct eee{
        ll id,value;
    }cx[maxn]; 
    ll n,m,q;
    long long  da[maxn];
    ll siz[maxn];
    ll f[maxn];
    int cmp(struct sss x,struct sss y){
        return x.z<y.z;
    } 
    int cmp1(struct eee x,struct eee y){
        return x.value<y.value;
    }
    int find(int x){
        if(x==f[x]) return x;
        else return f[x]=find(f[x]);
    }
    int main(){
        scanf("%lld%lld",&n,&m);
        for(int i=0;i<n-1;i++){
            scanf("%lld%lld%lld",&a[i].x,&a[i].y,&a[i].z);
        }
        sort(a,a+n-1,cmp);
        for(int i=0;i<m;i++){
            cx[i].id=i;
            scanf("%lld",&cx[i].value);
        }
        sort(cx,cx+m,cmp1);
        for(int i=1;i<=n;i++){
            f[i]=i;
            siz[i]=1;
        }
        /*for(int i=0;i<n-1;i++){
            printf("%d %d %d
    ",a[i].x,a[i].y,a[i].z);
        }*/ 
        ll dex=0;
        ll sum=0;
        for(int i=0;i<n-1;i++){
            if(a[i].z<=cx[dex].value){
                int xx=find(a[i].x);
                int yy=find(a[i].y);
                if(xx!=yy){
                    sum+=siz[xx]*siz[yy];
                    f[yy]=xx;
                    siz[xx]+=siz[yy];
                }
            } 
            else{
                da[cx[dex].id]=sum;
                dex++;
                if(dex==m) break;
                i--;
            }
        }
        for(;dex<m;dex++){
            da[cx[dex].id]=sum;
        } 
        for(int i=0;i<m;i++){
            printf("%lld ",da[i]);
        }
    } 
  • 相关阅读:
    P1032 字串变换
    P3203 [HNOI2010]弹飞绵羊
    P3690 【模板】Link Cut Tree (动态树)
    P2147 [SDOI2008]洞穴勘测
    P3950 部落冲突
    Codeforces Round #469 Div. 2题解
    线段树
    SDOI2018退役记
    4.1模拟题
    无旋Treap
  • 原文地址:https://www.cnblogs.com/Lis-/p/11469799.html
Copyright © 2011-2022 走看看