CF915F Imbalance Value of a Tree

题目大意:给出一棵树,其中每个点有其点权。求树上每对点间路径上的极差之和。

题解:鉴于n<=1e6,O( n ^ 2)的算法会T飞。因此可以考虑将极差拆为sigma max - sigma min。

因此得出这样一个做法:

第一步,将点按点权排序。

第二步,从小到大向图中加点,用并查集维护块的大小,此时新块中的新点对路径上最大值就是新点的权值。

第三步,同第二步求最小值。

最后相减。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 1000050
#define ll long long
inline int rd()
{
    int f=1,c=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=10*c+ch-'0';ch=getchar();}
    return f*c;
}
int n,v[N],hed[N],cnt;
struct EG
{
    int to,nxt;
}e[2*N];
void ae(int f,int t)
{
    e[++cnt].to = t;
    e[cnt].nxt = hed[f];
    hed[f] = cnt;
}
ll ans;
struct node
{
    int x;
}p[N];
bool cmp1(node a,node b)
{
    return v[a.x] < v[b.x];
}
int fa[N],siz[N];
bool vis[N];
int findfa(int x)
{
    if(x==fa[x])return x;
    return fa[x]=findfa(fa[x]);
}
int main()
{
    n=rd();
    for(int i=1;i<=n;i++)v[i]=rd();
    for(int f,t,i=1;i<n;i++)
    {
        f=rd(),t=rd();
        ae(f,t),ae(t,f);
    }
    for(int i=1;i<=n;i++)
    {
        p[i].x=i;
        fa[i]=i;
        siz[i]=1;
    }
    sort(p+1,p+1+n,cmp1);
    for(int i=1;i<=n;i++)
    {
        int u = p[i].x;
        vis[u]=1;
        ll tmp1=0,tmp2=0;
        for(int j=hed[u];j;j=e[j].nxt)
        {
            int to = e[j].to;
            if(!vis[to])continue;
            int ff = findfa(to);
            siz[u]+=siz[ff];
            tmp1+=1ll*siz[ff],tmp2+=1ll*siz[ff]*siz[ff];
            fa[ff]=u;
        }
        ans+=1ll*v[u]*tmp1;
        tmp1 = tmp1*tmp1;
        ans+=1ll*v[u]*(tmp1-tmp2)/2;
    }
    for(int i=1;i<=n;i++)
    {
        fa[i]=i;
        vis[i]=0;
        siz[i]=1;
    }
    for(int i=n;i>=1;i--)
    {
        int u = p[i].x;
        vis[u]=1;
        ll tmp1 = 0,tmp2 = 0;
        for(int j=hed[u];j;j=e[j].nxt)
        {
            int to = e[j].to;
            if(!vis[to])continue;
            int ff = findfa(to);
            siz[u]+=siz[ff];
            tmp1 += 1ll*siz[ff],tmp2+=1ll*siz[ff]*siz[ff];
            fa[ff] = u;
        }
        ans-=1ll*v[u]*tmp1;
        tmp1 = tmp1*tmp1;
        ans-=1ll*v[u]*(tmp1-tmp2)/2;
    }
    printf("%lld\n",ans);
    return 0;
}

 

posted @ 2018-10-23 20:29  LiGuanlin  阅读(136)  评论(0编辑  收藏  举报