2023NOIP A层联测16 货物运输

2023-10-25 03:28

本文主要是介绍2023NOIP A层联测16 货物运输,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目大意

有一个有 n n n个点 m m m条边的无向连通图,每条边的长度为 w i w_i wi,并且任意一条边最多在一个简单环内。每个点都有 s i s_i si个单位的资源,你想要均分这些资源,即让每座城市的资源数等于 ∑ s i n \dfrac{\sum s_i}{n} nsi(数据保证 ∑ s i n \dfrac{\sum s_i}{n} nsi是整数)。

已知将每个单位的资源运输到相邻城市需要花费道路长度 w i w_i wi的代价,求使得资源均分的最小代价。

1 ≤ n ≤ 1 0 5 , n − 1 ≤ m ≤ 2 n − 2 , 0 ≤ w i , s i ≤ 1 0 4 1\leq n\leq 10^5,n-1\leq m\leq 2n-2,0\leq w_i,s_i\leq 10^4 1n105,n1m2n2,0wi,si104


题解

首先,我们可以求出这个图的所有点双连通分量。然后,建一个新的图,在图上将每个点双连通分量建一个虚拟点,这个虚拟点和原图中点双连通分量中的点连边。

举个例子,我们来看下面这个图。

在这里插入图片描述

其中, { 1 , 2 , 3 } \{1,2,3\} {1,2,3}是一个点双连通分量, { 3 , 4 } \{3,4\} {3,4}是一个点双连通分量,那么我们将这两个点双连通分量虚拟成点,按上述方法连边,得到的图为

在这里插入图片描述

我们可以发现,这个图是一棵树。因为如果不是一棵树的话,那图上必定有一个环,那这个环又可以构成一个新的点双连通分量,矛盾。所以这个图一定是一棵树。

因为任意一条边最多在一个简单环内,所以这些点双连通分量其实都是一个环(也有可能是两个相连的点,这种情况特殊处理一下即可)。那么,我们对树的部分和每个点双连通分量的部分分别处理即可。

我们发现,这个新图的树边在原图对应的其实都是自己连向自己的,所以边权为 0 0 0。所以在树上只需要上传下面多出的资源(或者上传下面需要的资源),不需要统计对答案的贡献。那怎么上传呢?设点 u u u的子树内的有 s u m u sum_u sumu个单位的资源,有 s i z u siz_u sizu个点,则子树中只需要 a v g × s i z u avg\times siz_u avg×sizu个单位的资源(其中 a v g = ∑ s i n avg=\dfrac{\sum s_i}{n} avg=nsi),其余 s u m u − a v g × s i z u sum_u-avg\times siz_u sumuavg×sizu个单位的资源一定会往上传(如果值为负的话就是要往下传这个数的绝对值)。

然后,我们考虑每个点双连通分量要怎么处理。对于新图中每个表示点双连通分量的虚拟点,在遍历完它的子树之后,除了这个虚拟点的父亲之外,这个虚拟点直接连向的所有点(也就是原图中其表示的点双连通分量中的点)的 s i s_i si都已经确定了,而这个虚拟点的父亲有可能还会往其他地方传资源。

但是,我们是可以确定虚拟点的父亲往其他部分传完资源后剩下的资源的。我们假设这个环之外的部分都已经处理好了(就是环之外的点所含的资源都已经为 a v g avg avg),那么环上的点的资源之和就是环上的点数乘 a v g avg avg。不妨设环上每个点的编号为 1 , 2 , … , k 1,2,\dots,k 1,2,,k,一号点为新图中虚拟点的父亲所表示的点,设 a i = s i − a v g a_i=s_i-avg ai=siavg,则最终要使环上所有点的 a i a_i ai变为 0 0 0,那么此时必定满足 ∑ i = 1 k a i = 0 \sum\limits_{i=1}^ka_i=0 i=1kai=0。而 a 2 , a 3 , … , a k a_2,a_3,\dots,a_k a2,a3,,ak都是已经确定的,那么 a 1 = − ∑ i = 2 k a i a_1=-\sum\limits_{i=2}^ka_i a1=i=2kai

那么,我们现在已经得出环上每个点的 a i a_i ai,其表示这个点当前的资源与 a v g avg avg的差,下面考虑怎么才能让所有 a i a_i ai都等于 0 0 0

x i x_i xi表示 i i i i − 1 i-1 i1运输的资源数量,当 x i < 0 x_i<0 xi<0时表示从 i − 1 i-1 i1 i i i运输 ∣ x i ∣ |x_i| xi个单位的资源。那么,可以列出方程组:

{ a 1 − x 1 + x 2 = 0 a 2 − x 2 + x 3 = 0 ⋯ ⋯ a n − x n + x 1 = 0 \left\{\begin{matrix} a_1-x_1+x_2=0 \\ a_2-x_2+x_3=0 \\ \cdots \ \cdots \\ a_n-x_n+x_1=0 \end{matrix}\right. a1x1+x2=0a2x2+x3=0 anxn+x1=0

解得

{ x 2 = x 1 − a 1 x 3 = x 2 − a 2 = x 1 − a 1 − a 2 ⋯ ⋯ x n = x 1 − a 1 − a 2 − ⋯ − a n − 1 \begin{cases} x_2=x_1-a_1 \\ x_3=x_2-a_2=x_1-a_1-a_2 \\ \cdots \ \cdots \\ x_n=x_1-a_1-a_2-\cdots-a_{n-1} \end{cases} x2=x1a1x3=x2a2=x1a1a2 xn=x1a1a2an1

因此,每个 x i x_i xi都可以用 x 1 x_1 x1表示: x i = x 1 + X i x_i=x_1+X_i xi=x1+Xi,那么最后的答案为 ∑ w i ∣ x 1 − X i ∣ \sum w_i|x_1-X_i| wix1Xi

那么,问题转化为求 x 1 x_1 x1的值,使得 ∑ w i ∣ x 1 − X i ∣ \sum w_i|x_1-X_i| wix1Xi最小。当 w i w_i wi都为 1 1 1时, x 1 x_1 x1直接取 X i X_i Xi的中位数;当 w i w_i wi不都为 1 1 1时,可以看作有 w i w_i wi X i X_i Xi x 1 x_1 x1 ∑ w i \sum w_i wi个数的中位数。然后,求出 ∑ w i ∣ x 1 − X i ∣ \sum w_i|x_1-X_i| wix1Xi的值并用其更新答案即可。

注意要特判点双连通分量为两个相连的点的情况。

对于端点和边权分别为 u i , v i , w i u_i,v_i,w_i ui,vi,wi,我们可以用 m a p map map来存边权,即 m p [ u i ] [ v i ] = w i mp[u_i][v_i]=w_i mp[ui][vi]=wi,这样可以很方便地调用边权。

时间复杂度为 O ( ( n + m ) log ⁡ n ) O((n+m)\log n) O((n+m)logn)

code

#include<bits/stdc++.h>
using namespace std;
const int N=100000,M=200000;
int n,m,avg=0,tot=0,d[2*M+5],l[2*M+5],r[N+5],z[N+5],s[N+5];
int ct=0,vt=0,tp=0,dfn[N+5],low[N+5],st[N+5],sum[2*N+5],siz[2*N+5];
long long ans=0;
struct node{int x,sum;
};
struct vp{int x,w;
};
map<int,int>mp[N+5];
vector<int>vd[2*N+5];
vector<node>p;
vector<vp>c;
bool cmp(vp ax,vp bx){return ax.x<bx.x;
}
void add(int xx,int yy){l[++tot]=r[xx];d[tot]=yy;r[xx]=tot;
}
void dfs1(int u,int fa){st[++tp]=u;low[u]=dfn[u]=++ct;for(int i=r[u];i;i=l[i]){int v=d[i];if(v==fa) continue;if(!dfn[v]){dfs1(v,u);low[u]=min(low[u],low[v]);if(dfn[u]<=low[v]){int th;++vt;do{th=st[tp];--tp;vd[vt].push_back(th);vd[th].push_back(vt);}while(th!=v);vd[vt].push_back(u);vd[u].push_back(vt);}}else low[u]=min(low[u],dfn[v]);}
}
void solve(){if(p.size()==2){ans+=1ll*mp[p[0].x][p[1].x]*abs(p[0].sum);return;}c.clear();int vx=0;c.push_back((vp){vx,mp[p.back().x][p.front().x]});int sum=mp[p.back().x][p.front().x];for(int i=1;i<p.size();i++){vx+=p[i-1].sum;c.push_back((vp){vx,mp[p[i-1].x][p[i].x]});sum+=mp[p[i-1].x][p[i].x];}sort(c.begin(),c.end(),cmp);int now=0,chx;for(int i=0;i<c.size();i++){now+=c[i].w;if(now>=(sum+1)/2){chx=c[i].x;break;}}for(int i=0;i<c.size();i++){ans+=1ll*abs(chx-c[i].x)*c[i].w;}
}
void dfs2(int u,int fa){if(u<=n){sum[u]=s[u];siz[u]=1;}for(int i=0;i<vd[u].size();i++){int v=vd[u][i];if(v==fa) continue;dfs2(v,u);sum[u]+=sum[v];siz[u]+=siz[v];}if(u>n){p.clear();int sf=0;for(int i=0;i<vd[u].size();i++){int v=vd[u][i];if(v==fa) continue;p.push_back((node){v,siz[v]*avg-sum[v]});sf-=siz[v]*avg-sum[v];}p.push_back((node){fa,sf});solve();}
}
int main()
{
//	freopen("transfer.in","r",stdin);
//	freopen("transfer.out","w",stdout);scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%d",&s[i]);avg+=s[i];}avg/=n;for(int i=1,x,y,z;i<=m;i++){scanf("%d%d%d",&x,&y,&z);add(x,y);add(y,x);mp[x][y]=mp[y][x]=z;}vt=n;dfs1(1,0);dfs2(1,0);printf("%lld",ans);return 0;
}

这篇关于2023NOIP A层联测16 货物运输的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/279713

相关文章

【JavaScript】LeetCode:16-20

文章目录 16 无重复字符的最长字串17 找到字符串中所有字母异位词18 和为K的子数组19 滑动窗口最大值20 最小覆盖字串 16 无重复字符的最长字串 滑动窗口 + 哈希表这里用哈希集合Set()实现。左指针i,右指针j,从头遍历数组,若j指针指向的元素不在set中,则加入该元素,否则更新结果res,删除集合中i指针指向的元素,进入下一轮循环。 /*** @param

16 子组件和父组件之间传值

划重点 子组件 / 父组件 定义组件中:props 的使用组件中:data 的使用(有 return 返回值) ; 区别:Vue中的data (没有返回值);组件方法中 emit 的使用:emit:英文原意是:触发、发射 的意思components :直接在Vue的方法中声明和绑定要使用的组件 小炒肉:温馨可口 <!DOCTYPE html><html lang="en"><head><

react笔记 8-16 JSX语法 定义数据 数据绑定

1、jsx语法 和vue一样  只能有一个根标签 一行代码写法 return <div>hello world</div> 多行代码返回必须加括号 return (<div><div>hello world</div><div>aaaaaaa</div></div>) 2、定义数据 数据绑定 constructor(){super()this.state={na

打靶记录16——Momentum

靶机: https://download.vulnhub.com/momentum/Momentum.ova 下载后使用 VirtualBox 打开 难度:中 目标:取得 root 权限 + 2 Flag 攻击方法: 主机发现端口扫描信息收集Web 路径爆破XSS 漏洞JS 脚本分析AES 解密Redis 认证漏洞 主机发现 sudo arp-scan -l 端口扫描和服务发

NYOJ 16 矩形嵌套

OJ题目 : http://acm.nyist.net/JudgeOnline/problem.php?pid=16 描述 有n个矩形,每个矩形可以用a,b来描述,表示长和宽。矩形X(a,b)可以嵌套在矩形Y(c,d)中当且仅当a<c,b<d或者b<c,a<d(相当于旋转X90度)。例如(1,5)可以嵌套在(6,2)内,但不能嵌套在(3,4)中。你的任务是选出尽可能多的矩形排成一行,使得除

【硬刚ES】ES高级(16) 使用基础(4)安装(4) Linux 单机

本文是对《【硬刚大数据之学习路线篇】从零到大数据专家的学习指南(全面升级版)》的ES部分补充。 1 软件下载 软件下载地址:https://www.elastic.co/cn/downloads/past-releases/elasticsearch-7-8-0 2 软件安装 1) 解压软件 将下载的软件解压缩 # 解压缩tar -zxvf elasticsearch-7.8

LeetCode 16 3Sum Closest

题意: 给出数组s和目标target,要求从中选出3个数字,使其相加的和最接近target。 思路: x sum系列的题目,在这里做一个总结。 最经典的情况为2 sum问题,即给出s和target找出s[i] + s[j] = target。 可以使用枚举s[i]判断target - s[i]是否在s中出现且与s[i]不同的O(nlogn)方法,用map或排序后二分查找的方式均可。

iPhone 16或将不支持微信?谣言还是事实?

iPhone 16或将不支持微信?谣言还是事实? 近日,一则关于“iPhone 16可能不支持微信” 的传言如同一颗重磅炸弹,引爆了社交媒体,特别是在微博上,相关话题迅速占据热搜榜单,引发了无数网友的热议和担忧。然而,事实究竟如何?这背后又隐藏着哪些不为人知的博弈?今天,猫头虎技术团队就带大家一探究竟。 猫头虎是谁? 大家好,我是 猫头虎,别名猫头虎博主,擅长的技术领域包括云原生、前端、

萌新6:16进制世界(dp)

题目描述 这是一个16进制的世界,比如522的16进制是20A。 在5月22日那天,有人送给Bob一些月饼,每个月饼有饱食度和幸福度两个属性。 现在Bob有nnn个月饼,对于每个月饼iii,饱食度为viv_ivi​,幸福度为wiw_iwi​。 Bob现在有mmm饱食度,意味着他吃的月饼的饱食度之和不大于mmm。 但是由于Bob身处16进制的世界,他吃的月饼的幸福度之和必须是16的倍数。

【CRC校验】CRC-16/MODBUS 源码(查表法)

废话少说,直接上代码: 源码 /*************************** CRC校验函数 ***************************//* Table of CRC values for high-order byte */const uint8_t crcTableHigh[] = {0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x8