题目大意:给你一棵树,每个点有点权a_{i},求$\sum _{i=1}^{n} \sum _{j=i}^{n} f(i,j)$,$f(i,j)$表示i,j,路径上的点的最大权值-最小权值

正解的思路好神啊

正解:

首先,原式可以拆成$\sum _{i=1}^{n} \sum _{j=i}^{n} max(i,j) \; - \; \sum _{i=1}^{n} \sum _{j=i}^{n} min(i,j)$

max的求法和min类似,这里只讨论min的求法

把点按照从大到小排序,依次加入树里

感性理解成以当前点的点权作为最小值,那么这个点会向它周围已经被加入树里的联通块"扩散"去更新答案

答案就是这个点周围(剩余联通块的点数-当前联通块的点数)*点权,然后 剩余点数-当前联通块点数

也可以省去减法步骤,把最终答案除以二

并查集维护联通块即可,算上排序,总时间约为$O(nlogn)$

 #include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 1001000
#define ll long long
using namespace std; int gint()
{
int ret=,f=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ret=ret*+c-'';c=getchar();}
return ret*f;
}
int n,cte,tim;
int w[N],head[N],use[N];
int fa[N],sz[N];
void init(){for(int i=;i<=n;i++)fa[i]=i,sz[i]=;}
int find_fa(int x){
int y=x,pre;while(fa[y]!=y)y=fa[y];
while(fa[x]!=y){
pre=fa[x],fa[x]=y,x=pre;
}return y;
}
struct node{int id,val;}a[N];
struct Edge{int to,nxt;}edge[N*];
void ae(int u,int v){
cte++;edge[cte].nxt=head[u];
edge[cte].to=v,head[u]=cte;
}
int cmp(node s1,node s2){return s1.val<s2.val;} ll solve1()
{
sort(a+,a+n+,cmp);
int x,y,fx,fy;
init(); ll ans=;
for(int i=;i<=n;i++)
{
ll sum=;x=a[i].id;
for(int j=head[x];j;j=edge[j].nxt){
int v=edge[j].to;
if(use[v]){
fy=find_fa(v);
sum+=sz[fy];
}
}sum++;
for(int j=head[x];j;j=edge[j].nxt){
int v=edge[j].to;
if(use[v]){
fy=find_fa(v);
ans+=1ll*(sum-sz[fy])*sz[fy]*a[i].val;
sum-=sz[fy];
fa[fy]=x,sz[x]+=sz[fy];
}
}
use[x]=;
}return ans;
}
ll solve2()
{
memset(use,,sizeof(use));
int x,y,fx,fy;
init(); ll ans=;
for(int i=n;i>=;i--)
{
ll sum=;x=a[i].id;
for(int j=head[x];j;j=edge[j].nxt){
int v=edge[j].to;
if(use[v]){
fy=find_fa(v);
sum+=sz[fy];
}
}sum++;
for(int j=head[x];j;j=edge[j].nxt){
int v=edge[j].to;
if(use[v]){
fy=find_fa(v);
ans+=1ll*(sum-sz[fy])*sz[fy]*a[i].val;
sum-=sz[fy];
fa[fy]=x,sz[x]+=sz[fy];
}
}
use[x]=;
}return ans;
} int main()
{
scanf("%d",&n);
int x,y;
for(int i=;i<=n;i++)
w[i]=a[i].val=gint(),a[i].id=i;
for(int i=;i<n;i++)
x=gint(),y=gint(),ae(x,y),ae(y,x);
ll ans1=solve1();
ll ans2=solve2();
printf("%I64d\n",ans1-ans2);
return ;
}

CF915F Imbalance Value of a Tree (并查集)的更多相关文章

  1. 【CodeForces】915 F. Imbalance Value of a Tree 并查集

    [题目]F. Imbalance Value of a Tree [题意]给定n个点的带点权树,求所有路径极差的和.n,ai<=10^6 [算法]并查集 [题解]先计算最大值的和,按点权从小到大 ...

  2. [CF915F]Imbalance Value of a Tree

    [CF915F]Imbalance Value of a Tree 题目大意: 一棵\(n(n\le10^6)\)个结点的树,每个结点有一个权值\(w_i\).定义\(I(i,j)\)为\(i\)到\ ...

  3. Hdu.1325.Is It A Tree?(并查集)

    Is It A Tree? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) To ...

  4. Is It A Tree?(并查集)

    Is It A Tree? Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 26002   Accepted: 8879 De ...

  5. CF109 C. Lucky Tree 并查集

    Petya loves lucky numbers. We all know that lucky numbers are the positive integers whose decimal re ...

  6. HDU 5606 tree 并查集

    tree 把每条边权是1的边断开,发现每个点离他最近的点个数就是他所在的连通块大小. 开一个并查集,每次读到边权是0的边就合并.最后Ans​i​​=size[findset(i)],size表示每个并 ...

  7. [Swust OJ 856]--Huge Tree(并查集)

    题目链接:http://acm.swust.edu.cn/problem/856/ Time limit(ms): 1000 Memory limit(kb): 10000 Description T ...

  8. Codeforces Round #363 (Div. 2)D. Fix a Tree(并查集)

    D. Fix a Tree time limit per test 2 seconds memory limit per test 256 megabytes input standard input ...

  9. Is It A Tree?(并查集)(dfs也可以解决)

    Is It A Tree? Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Submi ...

随机推荐

  1. TensorFlow初学

    TensorFlow初学 基本概念 1.激活函数和成本函数 激活函数(activation function):一般是非线性函数,就是每个神经元通过这个函数将原有的来自其他神经的输入做一个非线性变化, ...

  2. Hihocoder1061-Beautiful String

    时间限制:10000ms单点时限:1000ms内存限制:256MB 描述 We say a string is beautiful if it has the equal amount of 3 or ...

  3. 全文检索lucene6.1的检索方式

    背景: 工作任务完成后,闲暇之计给自己充充电! Lucene是一个纯java全文检索工具包,采用倒排索引原理. 全文检索:指的是计算机索引程序通过扫描文章的每一个词,对每一个词建立一个索引,并指明该词 ...

  4. faker smtp server

    import os import asyncio import logging import base64 from email import message_from_bytes from emai ...

  5. python3 列表操作

    - 创建列表 #创建列表: list1 = [1, 2, 3, 4, 5] - 向列表中添加元素 - append # 向列表中添加元素: list1 = [1, 2, 3, 4, 5] list1. ...

  6. 使用uglifyjs压缩JS

    一般vue项目完成打包以后需要优化,特别是首次打开加载速度们,webpack打包以后js文件体积很大等方法,可以用这个方法来压缩js文件 安装node.js 安装当前应用 -- uglifyjs 如何 ...

  7. Java基础学习总结(58)——JAVA堆、栈详解

    关于堆栈的内容网上已经有很多资料了,这是我找的加上自己理解的一篇说明文: 一.内存区域类型 1.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制: 1. 栈:存放基本类型的变量数 ...

  8. Qt程序打包成exe可执行文件

    很多Qt爱好者想发布自己的Qt软件,但却发现在其他没有安装Qt SDK的机器上无法运行,这就是本文想要说明的问题.现在网上大部分软件都要发布自己开发的应用程序,都会打包到exe文件中,待安装完exe文 ...

  9. 拿到offer过后--大学最后时光最想做的那十件事

    昨天--2014.10.26,历史性的一刻,激动的签了欢聚时代(YY)的前端开发offer,工作地点是我喜欢的珠海(仅仅由于那边有我所向往的海还有自行车队,如今想想都乐开怀了,绕着海边骑单车的感觉真妙 ...

  10. 外网主机如何将数据包发送到共用一个公网IP的局域网某特定主机上的

    内网的一台电脑要上因特网对外开放服务或接收数据.都须要port映射.port映射分为动态和静态. 动态port映射:内网中的一台电脑要訪问站点.会向NAT网关发送数据包.包头中包含对方站点IP.por ...