题目

传送门:有账号才行。

题目描述
幻想乡有 NNN 个区域,从 111 到 NNN 编号,神奈子希望通过修建“御神渡”来让所有的区域互相可达,“御神渡”可以看做两个区域之间的一个双向道路。在 iii 区域与 jjj 区域之间修建“御神渡”,需要在 iii 区域耗费 CiC_iCi​ 的神力新建神社,在 jjj 区域耗费 CjC_jCj​ 的神力新建神社,然后将两个神社配对。如果一个区域和其他多个区域建立“御神渡”,那么在这个区域要为每个“御神渡”建一个神社,即多个“御神渡”不能共用神社。

“御神渡”会促进两个区域的人口流动,而人口的流动就会带来文化的交流、信仰的增多。如果 iii 区域的人口为 AiA_iAi​ 而 jjj 区域有的人口为 AjA_jAj​ ,则神奈子将会得到 Ai×AjA_i\times A_jAi​×Aj​ 的神力。

神奈子希望修建尽量少的“御神渡”,使得 NNN 个区域互相可达。在这个前提下,神奈子还希望自己总神力的减少量最小(注意该值可能为负,即神奈子的神力不减反增)。

输入格式
第一行一个非负整数 NNN ,表示区域的数量。

第二行 NNN 个非负整数 AiA_iAi​ ,分别表示 NNN 个区域的人口。数据保证每个区域的人口互不相等。

第三行 NNN 个非负整数 CiC_iCi​ ,分别表示在 NNN 个区域建神社要花费的神力。

输出格式
输出一个整数,表示神奈子总神力的减少量的最小值。

数据范围与约定
对于所有数据,N≤105,Ai≤2×106,Ci≤109N\le 10^5,A_i\le 2\times10^6,C_i\le 10^9N≤105,Ai​≤2×106,Ci​≤109 。

思路

很明显,将 (u,v)(u,v)(u,v) 的边权视作 Cu+Cv−Au×AvC_u+C_v-A_u\times A_vCu​+Cv​−Au​×Av​(即在 uuu 和 vvv 之间建立“御神渡”的净花费),则原题等价于求这张图里的最小生成树。

耿直的暴力

暴力求最小生成树,O(n2)\mathcal O(n^2)O(n2) 。因为是完全图。

斜率优化

思考为什么这道题可以有比最小生成树更快的算法?必然是因为 边权的特殊性

不难证明,所有与 uuu 相连的边中最小的一条一定是生成树中的边。(可以用 prim\tt primprim 或 kruskal\tt kruskalkruskal 的过程证明,或模仿二者的反证法来证明)。怎么找最小的一条边?

考虑 斜率优化。推一推斜率优化的式子,发现是 Cu−Cv<Ax(Au−Av)C_u-C_v<A_x(A_u-A_v)Cu​−Cv​<Ax​(Au​−Av​) 时 uuu 更优(考虑边 ⟨x,u⟩\langle x,u\rangle⟨x,u⟩ 和 ⟨x,v⟩\langle x,v\rangle⟨x,v⟩ 谁边权更小)。那么假定 Av<AuA_v<A_uAv​<Au​ ,第 xxx 个点定义为 (Cx,Ax)(C_x,A_x)(Cx​,Ax​) ,上式等价于 Kuv<AxK_{uv}<A_xKuv​<Ax​ 。不难发现,维护的形状是下凸包。

先求凸包,按照 AAA 值排序后跑,O(nlog⁡n)\mathcal O(n\log n)O(nlogn) 。然而现实很残酷——只有 60pts\tt{60pts}60pts !

改进版

为什么不是 100100100 分到手?因为有可能 试图连接自环

也就是说,斜率优化求决策点的时候,最佳决策点是自己 我也很绝望啊。

那么我们迫切的需要一个新方法:考虑每一个点的时候,只把其他的拿出来做凸包。回到了O(n2)\mathcal O(n^2)O(n2) ……

等等!好像对于 [1,mid][1,mid][1,mid] 中的每一个 xxx ,(mid,r](mid,r](mid,r] 中的任意一个点都可以当做决策点。这提示我们 分治

用 work(l,r)work(l,r)work(l,r) 表示处理 [l,r][l,r][l,r] 内部的互相贡献,首先递归,其次 交叉计算贡献

这很像 cdq\tt{cdq}cdq分治,能做到 O(nlog⁡n)\mathcal O(n\log n)O(nlogn) 。应该有 808080 分了吧?

正解

为什么还不过,去™的垃圾题

因为 连接一次不够……有可能只连接了 n2\frac{n}{2}2n​ 条边(两个点 选择了同一条边……)

好吧,把点染色,一个联通块中的点染一种颜色,问题转化为 某一颜色向异色点中连边

我们把颜色拿来排个序,一样可以分治……个屁!为什么不能分治了?因为交叉计算贡献的时候,得依靠 AAA 值有序才行!

这个问题好像有点熟悉……有两个维度 (x,y)(x,y)(x,y),要求 xxx 和 yyy 都有序。二维偏序

做过二维偏序板题吗?做过的都明白用的方法是 cdq\tt cdqcdq分治

现在这个题,好像有点板?(大雾)

CDQCDQCDQ 分治,先对颜色排序,再归并 AAA ,O(nlog⁡2n)\mathcal O(n\log^2 n)O(nlog2n) 。

关于复杂度:当前有 mmm 种颜色,则至少连接 m2\frac{m}{2}2m​ 条边,也就是颜色减少一半。开始有 nnn 种颜色,最多做 log⁡n\log nlogn 次生成树。生成树复杂度与上解法三同,O(nlog⁡n)\mathcal O(n\log n)O(nlogn) 。实际上,很少有数据能够卡到做 log⁡n\log nlogn 次生成树(大多数做个 222 到 555 次就搞定了),运行起来海星。

代码

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;struct Point{ // 向量(或者点)int x, y;Point(int X=0,int Y=0):x(X),y(Y){ }Point operator+(const Point &that)const{return Point(x+that.x,y+that.y);}Point operator-(const Point &that)const{return Point(x-that.x,y-that.y);}friend long long operator*(const Point &a,const Point &b){return 1ll*a.x*b.y-1ll*a.y*b.x;}friend Point operator*(const int &u,const Point &v){return Point(u*v.x,u*v.y);}
};const int MaxN = 100000;
int allColor, n, fa[MaxN];
inline int findColor(int a){if(fa[a] != a) // 并查集判断颜色相同否fa[a] = findColor(fa[a]);return fa[a];
}
struct Node{Point p; int color;bool operator < (const Node &that)const{if(color != that.color)return color < that.color;return this->lessThan(that);}bool lessThan(const Node &that)const{return p.x < that.p.x;}
} node[MaxN];long long edgeValue(int i,int j){ // 暴力计算边的权值return -1ll*node[i].p.x*node[j].p.x+node[i].p.y+node[j].p.y;
}
int ys[MaxN]; // 将颜色离散化
int* convexHull(int l,int r,int *result){int *top = result;for(int i=l; i<r; ++i){while(top-result >= 2)if((node[i].p-node[*(top-1)].p)*(node[*(top-1)].p-node[*(top-2)].p) >= 0)-- top; // 维护下凸包else break;*(top ++) = i;}return top;
}
int temp[MaxN];
pair<long long,int> choice[MaxN];
Node temp2[MaxN]; // to sort it
void dealWith(int L,int R,int l,int r){// [L,R] for color. [l,r) for index.if(L == R) return ;int MID = (L+R)>>1, mid;for(mid=l; mid<r; ++mid)if(ys[node[mid].color] > MID)break;dealWith(L,MID,l,mid); // left partdealWith(MID+1,R,mid,r); // right partPoint xl; // Kfor(int i=mid, *now=temp, *tail=convexHull(l,mid,temp); i<r; ++i){xl = Point(1,node[i].p.x);while(tail-now >= 2)if((node[*(now+1)].p-node[*now].p)*xl >= 0)++ now; else break;// choice: first是边权, second是与谁相连if(choice[node[i].color].second == -1 or edgeValue(i,*now) < choice[node[i].color].first)choice[node[i].color] = make_pair(edgeValue(i,*now),node[*now].color);}for(int i=l, *now=temp, *tail=convexHull(mid,r,temp); i<mid; ++i){xl = Point(1,node[i].p.x);while(tail-now >= 2)if((node[*(now+1)].p-node[*now].p)*xl >= 0)++ now;else break;if(choice[node[i].color].second == -1 or edgeValue(i,*now)<choice[node[i].color].first)choice[node[i].color] = make_pair(edgeValue(i,*now),node[*now].color);}for(int i=l, j=mid, k=l; i<mid or j<r; )if(j == r or (i < mid and node[i].lessThan(node[j])))temp2[k ++] = node[i ++];else // 将其排序temp2[k ++] = node[j ++];for(int i=l; i<r; ++i)node[i] = temp2[i];
}
long long ans = 0;
bool setMST(){for(int i=0; i<n; ++i){fa[i] = i; ys[i] = 0;choice[i].second = -1;}sort(node,node+n); allColor = 0;for(int i=0; i<n; ){ys[node[i].color] = ++allColor;for(; i<n and ys[node[i].color] == allColor; ++i);}if(allColor == 1)return true; // finished!dealWith(1,allColor,0,n);for(int i=0; i<n; ++i){if(not ys[node[i].color])continue;ys[node[i].color] = 0;if(choice[choice[node[i].color].second].second == node[i].color and node[i].color > choice[node[i].color].second)continue; // they two choose the same edgefa[node[i].color] = choice[node[i].color].second;ans += choice[node[i].color].first;}for(int i=0; i<n; ++i)node[i].color = findColor(node[i].color);return false;
}int main(){scanf("%d",&n);for(int i=0; i<n; ++i){node[i].color = i;scanf("%d",&node[i].p.x);}for(int i=0; i<n; ++i)scanf("%d",&node[i].p.y);while(not setMST());cout << ans;return 0;
}

[usOJ5677]御神渡相关推荐

  1. 御神楽的学习记录之Springboot+netty实现Web聊天室

    文章目录 前言 一.Netty简介 1.介绍 二.Web聊天室实现 1.Idea项目创建 2.java类编写 3.html测试 总结 参考 前言 WebSocket是一种在单个TCP连接上进行全双工通 ...

  2. 2019.09.21 多校联合训练(提高组)

    东方记者 一.题目 [题目描述] 这一天,在幻想乡发生了N起大新闻,第i起大新闻发生在坐标(Xi,Yi)处.射命丸文从坐标(0,0)处出发,按照新闻发生的时间顺序前往各个新闻发生地收集资料,最后回到坐 ...

  3. 故事・ことわざ・四字熟語a

    ああいえばこういう (ああ言えばこう言う) あいえんきえん (愛縁奇縁) あいえんきえん (逢縁機縁) あいえんきえん (合縁奇縁) あいえんきえん (相縁奇縁) あいきゅうおくう (愛及屋烏) あい ...

  4. 仙剑奇侠传编年史(转自网络)

    B站仙剑编年史视频:点击打开链接 1.上古时期(公元前?-前206年) 炎黄时代(约公元前2070年以前) 盘古开天辟地.太古巨龟蓬莱与天地几乎同时诞生.盘古死后精.气.神化成伏羲.神农和女娲,被称为 ...

  5. 《黃帝內經》第一章《上古天真論》

    上医治国,中医治人,下医治病   <黄帝内经>分<素问><灵枢(shu)>上下两部,每部各81篇.素问,就是我们现在的FAQ(Frequently Asked Qu ...

  6. 【无浪】自己用C++实现的零游戏的战斗(半成品)

    大一下学期的时候迷上了零的游戏.然后下半学期自己尝试着实现了零的一部分战斗系统,只是黑白界面而已.实现算法挺幼稚的,只是单调枯燥的重复工作,抽着空自己纯手编出来,当时大都把知识点都记牢了,当时刚学完C ...

  7. 基于Java的Minecraft游戏后端自定义插件 05事件监听器

    事件监听器 内容简介 事件监听器 内容简介 事件监听器 文档中org.bukkit.event都是事件包 https://www.youtube.com/watch?v=PWQNsqwD-AY. pu ...

  8. 【JAVA 文件概述】

    一.概述 使用此类的原因: 该类将文件或者文件夹封装成对象. 方便对文件与文件夹的属性信息进行操作. File对象作为参数传递给流的构造函数. 要求:使用File类的常用方法. windows平台下, ...

  9. 《黄帝内经》的养生之道

    启玄子王冰撰夫释缚脱艰,全真导气,拯黎元于仁寿,济赢劣以获安者,非三圣道则不能致之矣.孔安国序消书>日:伏炭.神农.黄帝之书,谓之三坟,言大道也.班固淑书·艺文志>曰:根帝内经>十八 ...

  10. 《黄帝内经.上古天真论》养生秘诀节选-1

    余闻上古之人,春秋皆度百岁,而动作不衰:今时之人,年半百而动作皆衰者,时世异耶?人将失之耶? 歧伯曰:上古之人,其知道者,法于阴阳,和于术数.食饮有节,起居有常,不妄作劳,故能形与神俱,而尽终其天年, ...

最新文章

  1. birt脚本for循环语句_Python初级教程(11): for循环语句
  2. Hadoop生态hive(五)Hive QL数据库
  3. 动态规划:从新手到专家
  4. 客制化键盘键位修改_IQUNIX Slim87 RGB机械键盘评测
  5. react中的state、props、ref
  6. Luogu4640 BJWC2008 王之财宝 容斥、Lucas
  7. 获取(可能)关联数组中的第一个键?
  8. 判断是否是微信浏览器
  9. 土地转移矩阵的计算步骤
  10. 申报火热进行中|2021“科创中国”开源创新榜评选
  11. 温州大学《机器学习》课件!
  12. CentOS官网 安装包下载
  13. 阿里网盘攻,百度网盘守
  14. java边界布局东南西北_第58节:Java中的图形界面编程-GUI
  15. SpringBoot之使用Security
  16. 银河5 号超级计算机,超级计算器前五名:中国“霸占”第一和第二【图】
  17. 用马克思主义看待现社会拜金主义价值观
  18. char byte java_java byte与char互转原理-转 | 学步园
  19. JUC--005--locks1
  20. 华为路由交换学习篇-STP生成树协议

热门文章

  1. 关于NTFS数据流ADS的详细介绍
  2. 别和我谈理想,我要的是钱
  3. python打印菱形_python打印菱形
  4. java程序员 thinkpad_JAVA程序员笔记本电脑推荐?
  5. 数学传奇3——神话的破灭
  6. 产业洞察 | 鸿蒙不会用于手机,网民有点心凉!解密操作系统造得出用不起的魔咒...
  7. 路由入口与vue布局入口
  8. 谷歌学术 rss_更改Google RSS文件夹
  9. 【计算机图形学】Bezier曲线软件及操作
  10. VR火灾隐患排查,模拟多种火灾场景