zoukankan      html  css  js  c++  java
  • 915F.Imbalance Value of a Tree(并查集+树上信息统计)

    您将得到由n个顶点组成的树T。 每个顶点上都有一个数字。 写在顶点i上的数字是ai。 让我们将函数I(x,y)表示为在连接顶点x和y的简单路径上ai的最大值和最小值之间的差。

    您的任务是计算。

    题解:

    考虑单独算每个点的贡献。

    把点权转化为边权,对于最大值的贡献,把每条边的边权设为两个点点权的较大值。然后将所有边从小到大排序,依次枚举,枚举的时候用并查集维护,每条边的贡献就是所连接的两个点的连通块点数乘积。

    算最小值的贡献同理。

    //定义两点间的边权为两点的最大值
    //然后将每条边从小到大排序
    //用并查集合并
    //每条边的贡献是当前所连接的两个连通块内的点数之积
    //最小值同理
    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e6+100;
    int n,a[maxn];
    struct node {
        int u,v,w;
        bool operator < (const node &r) const {
            return w<r.w;
        }
    }edge[2][maxn];
    int father[maxn],num[maxn]; 
    int findfather (int x) {
        int a=x;
        while (x!=father[x]) x=father[x];
        while (a!=father[a]) {
            int z=a;
            a=father[a];
            father[z]=x;
        }
        return x;
    }
    void Union (int x,int y) {
        x=findfather(x);
        y=findfather(y);
        if (x!=y) {
            father[x]=y;
            num[y]+=num[x];
            num[x]=0;
        }
    }
    int main () {
        scanf("%d",&n);
        for (int i=1;i<=n;i++) scanf("%d",a+i);
        for (int i=1;i<n;i++) {
            int u,v;
            scanf("%d%d",&u,&v);
            edge[0][i].u=u;
            edge[0][i].v=v;
            edge[0][i].w=max(a[u],a[v]);
            edge[1][i].u=u;
            edge[1][i].v=v;
            edge[1][i].w=min(a[u],a[v]);
        }
        long long ans=0;
        sort(edge[0]+1,edge[0]+n);
        for (int i=1;i<=n;i++) father[i]=i,num[i]=1;
        for (int i=1;i<n;i++) {
            int u=edge[0][i].u;
            int v=edge[0][i].v;
            ans+=1ll*edge[0][i].w*num[findfather(u)]*num[findfather(v)];
            Union(u,v);
        }
        for (int i=1;i<=n;i++) father[i]=i,num[i]=1;
        sort(edge[1]+1,edge[1]+n);
        for (int i=n-1;i>=1;i--) {
            int u=edge[1][i].u;
            int v=edge[1][i].v;
            ans-=1ll*edge[1][i].w*num[findfather(u)]*num[findfather(v)];
            Union(u,v);
        }
        printf("%lld
    ",ans);
    }
  • 相关阅读:
    ***:做人的基本原则(看完终身受益)
    ref和out的相同和不同的讨论
    关于继承和虚函数的入门讨论
    C#中利用ArrayList来对索引器访问越界情况进行内容的扩充处理
    [C#]实现IEnumerable接口来使用foreach语句的一个实例
    浅谈MSSQL锁机制
    jQuery图片分屏加载技术插件
    SET IDENTITY_INSERT [Table] [ON|OFF]
    SQL Server DATEPART() 函数
    常用的SQL语句对数据库进行操作
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/14359911.html
Copyright © 2011-2022 走看看