zoukankan      html  css  js  c++  java
  • CodeForces 915F Imbalance Value of a Tree

    题意

    给一棵 (n) 个点的树,点有点权,设 (max(x,y)) 表示 (x)(y) 路径中所有点的点权最大值,(min(x,y)) 表示路径上点权的最小值,求:

    [sumlimits_{i=1}^{n}sum limits_{j=i+1}^{n}(max(i,j)-min(i,j))]

    ( exttt{Data Range:}1leq nleq 10^6)

    题解

    简单题。

    将这个式子拆成两个,一个是所有的 (max),另一个是所有的 (min),然后分开求解。首先讨论 (max)

    如果是边权的话可以按照边权从小到大加边合并联通块。对于一条边 ((u,v,w)) 来说,它对答案的贡献是 (w imes sz_u imes sz_v),用并查集维护连通块的大小即可 (O(nlog n)) 完成。

    但是因为这个题是点权就不行,需要转化成边权。一个常见的 trick(但是我今天第一次接触到)是将连接 (u)(v) 的边的边权变成 (u,v) 两点点权的最大值,因为与一个数多次取 (max) 并不会改变最终结果。

    对于 (min) 来说也是一样的,于是这个题就做完了。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef int ll;
    typedef long long int li;
    const ll MAXN=1e6+51;
    struct Edge{
        ll from,to,mn,mx;
        inline bool operator <(const Edge &rhs)const
        {
            return mn>rhs.mn;
        }
        inline bool operator >(const Edge &rhs)const
        {
            return mx<rhs.mx;
        }
    };
    Edge ed[MAXN];
    ll n,from,to;
    li mx,mn;
    ll x[MAXN],ffa[MAXN],sz[MAXN];
    inline ll read()
    {
        register ll num=0,neg=1;
        register char ch=getchar();
        while(!isdigit(ch)&&ch!='-')
        {
            ch=getchar();
        }
        if(ch=='-')
        {
            neg=-1;
            ch=getchar();
        }
        while(isdigit(ch))
        {
            num=(num<<3)+(num<<1)+(ch-'0');
            ch=getchar();
        }
        return num*neg;
    }
    inline ll find(ll x)
    {
        return x==ffa[x]?x:ffa[x]=find(ffa[x]);
    }
    inline void merge(ll x,ll y)
    {
        ll fx=find(x),fy=find(y);
        fx!=fy?ffa[fy]=fx,sz[fx]+=sz[fy],sz[fy]=0:1;
    }
    int main()
    {
        n=read();
        for(register int i=1;i<=n;i++)
        {
            x[i]=read(),ffa[i]=i,sz[i]=1;
        }
        for(register int i=1;i<n;i++)
        {
            from=read(),to=read();
            ed[i]=(Edge){from,to,min(x[from],x[to]),max(x[from],x[to])};
        }
        sort(ed+1,ed+n);
        for(register int i=1;i<n;i++)
        {
            mn+=(li)sz[find(ed[i].from)]*sz[find(ed[i].to)]*ed[i].mn;
            merge(ed[i].from,ed[i].to);
        }
        sort(ed+1,ed+n,greater<Edge>());
        for(register int i=1;i<=n;i++)
        {
            ffa[i]=i,sz[i]=1;
        }
        for(register int i=1;i<n;i++)
        {
            mx+=(li)sz[find(ed[i].from)]*sz[find(ed[i].to)]*ed[i].mx;
            merge(ed[i].from,ed[i].to);
        }
        printf("%lld
    ",mx-mn);
    }
    
  • 相关阅读:
    java线程小结1
    String和StringBuffer
    java队列的实现
    java栈的实现
    java链表
    this与super关键字总结
    JVM内存杂记1
    面试题18:删除链表节点
    面试题17:打印从 1 到最大的 n 位数
    面试题16:数值的整数次方
  • 原文地址:https://www.cnblogs.com/Karry5307/p/13862710.html
Copyright © 2011-2022 走看看