题目大意:给你一棵树,每个点有点权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. hdu1542 矩形面积并(线段树+离散化+扫描线)

    题意: 给你n个矩形,输入每个矩形的左上角坐标和右下角坐标. 然后求矩形的总面积.(矩形可能相交). 题解: 前言: 先说说做这道题的感受: 刚看到这道题顿时就懵逼了,几何 烂的渣渣.后来从网上搜题解 ...

  2. easyui的增删改

    陈旧的开发模式PM:“我要这个功能”后端:“这个先找前端做个模板”前端:“模板做完了”后端:“我来对接一下,这里样式不对”前端:“我改完了”后端:“功能交付”PM:“春节要加这个活动”后端:“这个先找 ...

  3. Python笔记(28)-----继承

    来自https://blog.csdn.net/sunwukong_hadoop/article/details/80175292 1.Python的继承以及调用父类成员 python子类调用父类成员 ...

  4. [CodeForces]500B New Year Permutation

    刷水题做几道入门贪心题预热... 找联通块里字典序最小的放到最前面即可.记得写传递闭包 #include <iostream> #include <cstdio> #inclu ...

  5. vue 删除某个元素和删除某些元素

    今天做项目使用前端vue框架,需要循环遍历去删除一些数组元素.开始思想局限,一直纠结如何去循环删除,犹豫循环删除数组值下标会发生变化,并不是一种好的方法. 方法一:使用forEach 和 splice ...

  6. WordCount合作--自己部分

    前言: (1)合作者:201631062127,201631062625 (2)合作代码地址:WordCount 一.结对的PSP表格: PSP2.1 PSP阶段 预估耗时 (分钟) 实际耗时 (分钟 ...

  7. AMD包下载及使用

    AMD下载 下载地址 选择837.zip下载即可,将837.zib考入相应的文件夹下,并解压缩 wget http://netlib.org/toms/837.zip unzip 837.zip cd ...

  8. [luogu] P4551 最长异或路径(贪心)

    P4551 最长异或路径 题目描述 给定一棵\(n\)个点的带权树,结点下标从\(1\)开始到\(N\).寻找树中找两个结点,求最长的异或路径. 异或路径指的是指两个结点之间唯一路径上的所有边权的异或 ...

  9. Java代码实现MySQL数据库的备份与还原

    通常在MySQL数据库的备份和恢复的时候,多是采用在cmd中执行mysql命令来实现. 例如: mysqldump -h127.0.0.1 -uroot -ppass test > d:/tes ...

  10. Maven导入ojdbc14.jar和ojdbc6.jar

    Maven导入ojdbc14.jar和ojdbc6.jar 学习了:http://blog.csdn.net/johon_medison/article/details/51689690 在 ‘运行’ ...