[usOJ5677]御神渡
题目
传送门:有账号才行。
题目描述
幻想乡有 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(nlogn)\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(nlogn)\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(nlog2n)\mathcal O(n\log^2 n)O(nlog2n) 。
关于复杂度:当前有 mmm 种颜色,则至少连接 m2\frac{m}{2}2m 条边,也就是颜色减少一半。开始有 nnn 种颜色,最多做 logn\log nlogn 次生成树。生成树复杂度与上解法三同,O(nlogn)\mathcal O(n\log n)O(nlogn) 。实际上,很少有数据能够卡到做 logn\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]御神渡相关推荐
- 御神楽的学习记录之Springboot+netty实现Web聊天室
文章目录 前言 一.Netty简介 1.介绍 二.Web聊天室实现 1.Idea项目创建 2.java类编写 3.html测试 总结 参考 前言 WebSocket是一种在单个TCP连接上进行全双工通 ...
- 2019.09.21 多校联合训练(提高组)
东方记者 一.题目 [题目描述] 这一天,在幻想乡发生了N起大新闻,第i起大新闻发生在坐标(Xi,Yi)处.射命丸文从坐标(0,0)处出发,按照新闻发生的时间顺序前往各个新闻发生地收集资料,最后回到坐 ...
- 故事・ことわざ・四字熟語a
ああいえばこういう (ああ言えばこう言う) あいえんきえん (愛縁奇縁) あいえんきえん (逢縁機縁) あいえんきえん (合縁奇縁) あいえんきえん (相縁奇縁) あいきゅうおくう (愛及屋烏) あい ...
- 仙剑奇侠传编年史(转自网络)
B站仙剑编年史视频:点击打开链接 1.上古时期(公元前?-前206年) 炎黄时代(约公元前2070年以前) 盘古开天辟地.太古巨龟蓬莱与天地几乎同时诞生.盘古死后精.气.神化成伏羲.神农和女娲,被称为 ...
- 《黃帝內經》第一章《上古天真論》
上医治国,中医治人,下医治病 <黄帝内经>分<素问><灵枢(shu)>上下两部,每部各81篇.素问,就是我们现在的FAQ(Frequently Asked Qu ...
- 【无浪】自己用C++实现的零游戏的战斗(半成品)
大一下学期的时候迷上了零的游戏.然后下半学期自己尝试着实现了零的一部分战斗系统,只是黑白界面而已.实现算法挺幼稚的,只是单调枯燥的重复工作,抽着空自己纯手编出来,当时大都把知识点都记牢了,当时刚学完C ...
- 基于Java的Minecraft游戏后端自定义插件 05事件监听器
事件监听器 内容简介 事件监听器 内容简介 事件监听器 文档中org.bukkit.event都是事件包 https://www.youtube.com/watch?v=PWQNsqwD-AY. pu ...
- 【JAVA 文件概述】
一.概述 使用此类的原因: 该类将文件或者文件夹封装成对象. 方便对文件与文件夹的属性信息进行操作. File对象作为参数传递给流的构造函数. 要求:使用File类的常用方法. windows平台下, ...
- 《黄帝内经》的养生之道
启玄子王冰撰夫释缚脱艰,全真导气,拯黎元于仁寿,济赢劣以获安者,非三圣道则不能致之矣.孔安国序消书>日:伏炭.神农.黄帝之书,谓之三坟,言大道也.班固淑书·艺文志>曰:根帝内经>十八 ...
- 《黄帝内经.上古天真论》养生秘诀节选-1
余闻上古之人,春秋皆度百岁,而动作不衰:今时之人,年半百而动作皆衰者,时世异耶?人将失之耶? 歧伯曰:上古之人,其知道者,法于阴阳,和于术数.食饮有节,起居有常,不妄作劳,故能形与神俱,而尽终其天年, ...
最新文章
- birt脚本for循环语句_Python初级教程(11): for循环语句
- Hadoop生态hive(五)Hive QL数据库
- 动态规划:从新手到专家
- 客制化键盘键位修改_IQUNIX Slim87 RGB机械键盘评测
- react中的state、props、ref
- Luogu4640 BJWC2008 王之财宝 容斥、Lucas
- 获取(可能)关联数组中的第一个键?
- 判断是否是微信浏览器
- 土地转移矩阵的计算步骤
- 申报火热进行中|2021“科创中国”开源创新榜评选
- 温州大学《机器学习》课件!
- CentOS官网 安装包下载
- 阿里网盘攻,百度网盘守
- java边界布局东南西北_第58节:Java中的图形界面编程-GUI
- SpringBoot之使用Security
- 银河5 号超级计算机,超级计算器前五名:中国“霸占”第一和第二【图】
- 用马克思主义看待现社会拜金主义价值观
- char byte java_java byte与char互转原理-转 | 学步园
- JUC--005--locks1
- 华为路由交换学习篇-STP生成树协议