• 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
    ",ans);
        return 0;
    }
  • 相关阅读:
    你的背包,被我找到了(01背包问题)
    一点微小的改动,让你从B树理解到B+树
    有哪些令人拍案叫绝的算法?
    来来来,今天教你们用 CV 算法整点好玩的...
    内存都没了,还能运行程序?
    我的常用软件大公开!
    漫画:美团面试题(整数拆分)
    科普:我就想写个爬虫,到底要学多少东西啊?
    腾讯和阿里在 B 站评论区相遇了!
    程序员注意:这个群可以学英语,还全程免费!
  • 原文地址:https://www.cnblogs.com/LiGuanlin1124/p/9839123.html
Copyright © 2020-2023  润新知