P10683 [COTS 2024] 划分 Particija

news/2025/11/22 16:50:52/文章来源:https://www.cnblogs.com/Tmbcan/p/19258102

思路

转化一下题意,\(a_i\)\(b_i\) 恰有一个限制被满足,变成在一个二分图上有一些边 \((a_i,b_i)\),求最小点覆盖。
\(k>0\) 时可以更改一条边的一个端点,使得最大或最小化最小点覆盖。

不难发现整个图是由若干二分图联通块组成的。

\(k=0\) 时,对每个二分图求最小点覆盖,直接 \(O(n)\) 黑白染色。

\(k=1\) 时,因为有 \((\min(x_1,y_1)+\min(x_2,y_2)) = \min(x_1+x_2,x_1+y_2,x_2+y_1,x_2+y_2) \le \min(x_1+x_2,y_1+y_2)\),这启发我们把一个块分成两个块才能使答案变小。
于是我们更改的点一定属于一条割边,然后我们考虑应该把这个端点挪移到哪里。

假如分成的两个连通块存在一个不是孤点,那么直接把更改的端点变成这个连通块里的点即可,这样做不会产生新的贡献。
如果分成的两个连通块都是孤点,那么更改这条边不会更优,代码实现上可以直接不管。
然后枚举每一条割边计算答案即可。

\(k=2\) 时,我们要合并两个连通块。
假如一个连通块左部点大于右部点,那么我们肯定找一个右部点大于左部点的块和它合并。每次贪心的拿右部点比左部点多的数量最多的出来匹配。
左部点数量小于右部点同理,找右部点比左部点少的数量最多的出来匹配。

所以我们枚举所有边,计算把它连给另一个连通块的贡献就行。
但是如果移动的这条边是割边,那还得额外再算分开连通块的贡献,然后再分别算分成的两个连通块和哪个连通块合并。

但是其实还有一个小问题,我们上面的不等式是基于总点数不变的。仔细阅读题面,发现我们的更改操作其实是可以新建节点的。这个问题在 \(k=1\) 的时候不会体现,因为新建节点只会让答案变大。
于是,我们还得再额外统计一下新建一个节点能产生的贡献,新建的节点必须和原节点的颜色一样。

最后记得特判 \(n=1\),此时无论如何不会存在两个连通块。

代码

怕写挂,遂对每一个包都重新写了 Tarjan 和统计答案。
\(k=2\) 含巨量分讨,慎看。

const int N = 4e5+10;
int n,a[N],b[N];
struct{int to,nex,from;
}edge[N<<1];
int head[N],edge_num;
inline void add(int x,int y){edge[++edge_num].to = y;edge[edge_num].nex = head[x];head[x] = edge_num;edge[edge_num].from = x;
}// k = 0namespace Sub0{
int cnt[2],vis[N];
inline void dfs(int now){cnt[now>n]++;vis[now] = 1;for(int i=head[now];i;i=edge[i].nex){int tto = edge[i].to;if(vis[tto]) continue;dfs(tto);}
}
inline void solve(int T){int ans = 0;for(int i=1;i<=n;++i) if(!vis[a[i]]){cnt[0] = cnt[1] = 0;dfs(a[i]);ans += Min(cnt[0],cnt[1]);}for(int i=1;i<=n;++i) if(!vis[b[i]+n]){cnt[0] = cnt[1] = 0;dfs(b[i]+n);ans += Min(cnt[0],cnt[1]);}printf("%d",ans);if(T) for(int i=1;i<=n+n;++i) vis[i] = 0;
}
}// k = 1namespace Sub1{
int dfn[N],low[N],dtop,is_cut[N];
int cnt[N][2],tmp[N][2];
inline void tarjan(int now,int fu,int tp){dfn[now] = low[now] = ++dtop;int flag = 0;cnt[tp][now>n]++;for(int i=head[now];i;i=edge[i].nex){int tto = edge[i].to;if(!dfn[tto]){tarjan(tto,now,tp);low[now] = Min(low[now],low[tto]);if(low[tto]>dfn[now]) is_cut[tto] = 1;}else{if(tto!=fu || flag) low[now] = Min(low[now],dfn[tto]);else flag = 1;}}
}
int num,ans;
inline void get_ans(int now,int tp){tmp[now][now>n]++;for(int i=head[now];i;i=edge[i].nex){int tto = edge[i].to;if(tmp[tto][0]+tmp[tto][1]) continue;get_ans(tto,tp);tmp[now][0] += tmp[tto][0];tmp[now][1] += tmp[tto][1];if(is_cut[tto]){ans = Min(ans,num-Min(cnt[tp][0],cnt[tp][1])+Min(tmp[tto][0],tmp[tto][1])+Min(cnt[tp][0]-tmp[tto][0],cnt[tp][1]-tmp[tto][1]));} }
}
inline void solve(int T){for(int i=1;i<=n;++i) if(!dfn[a[i]]){cnt[a[i]][0] = cnt[a[i]][1] = 0;tarjan(a[i],a[i],a[i]);num += Min(cnt[a[i]][0],cnt[a[i]][1]);}for(int i=1;i<=n;++i) if(!dfn[b[i]+n]){cnt[b[i]+n][0] = cnt[b[i]+n][1] = 0;tarjan(b[i]+n,b[i]+n,b[i]+n);num += Min(cnt[b[i]+n][0],cnt[b[i]+n][1]);}ans = num;for(int i=1;i<=n;++i) if(!(tmp[a[i]][0]+tmp[a[i]][1])) get_ans(a[i],a[i]);for(int i=1;i<=n;++i) if(!(tmp[b[i]+n][0]+tmp[b[i+n]][1])) get_ans(b[i]+n,b[i]+n);printf("%d",ans);if(T){dtop = num = 0;for(int i=1;i<=n+n;++i){low[i] = dfn[i] = is_cut[i] = 0;cnt[i][0] = cnt[i][1] = 0;tmp[i][0] = tmp[i][1] = 0;}}
}
}// k = 2namespace Sub2{
int dfn[N],low[N],dtop,is_cut[N];
int cnt[N][2],tmp[N][2];
inline void tarjan(int now,int fu,int tp){dfn[now] = low[now] = ++dtop;int flag = 0;cnt[tp][now>n]++;for(int i=head[now];i;i=edge[i].nex){int tto = edge[i].to;if(!dfn[tto]){tarjan(tto,now,tp);low[now] = Min(low[now],low[tto]);if(low[tto]>dfn[now]) is_cut[tto] = 1;}else{if(tto!=fu || flag) low[now] = Min(low[now],dfn[tto]);else flag = 1;}}
}
int minn[2],maxn[2],num,ans;
inline void get_ans(int now,int tp){tmp[now][now>n]++;for(int i=head[now];i;i=edge[i].nex){int tto = edge[i].to;if(tmp[tto][0]+tmp[tto][1]) continue;get_ans(tto,tp);tmp[now][0] += tmp[tto][0];tmp[now][1] += tmp[tto][1];if(is_cut[tto]){if(cnt[tp][0]-tmp[tto][0]>cnt[tp][1]-tmp[tto][1]){ans = Max(ans,num-Min(cnt[tp][0],cnt[tp][1])-Min(minn[0],minn[1])+Min(tmp[tto][0],tmp[tto][1])+Min(cnt[tp][0]-tmp[tto][0]+minn[0],cnt[tp][1]-tmp[tto][1]+minn[1]));}else{ans = Max(ans,num-Min(cnt[tp][0],cnt[tp][1])-Min(maxn[0],maxn[1])+Min(tmp[tto][0],tmp[tto][1])+Min(cnt[tp][0]-tmp[tto][0]+maxn[0],cnt[tp][1]-tmp[tto][1]+maxn[1]));}if(tmp[tto][0]>tmp[tto][1]){ans = Max(ans,num-Min(cnt[tp][0],cnt[tp][1])-Min(minn[0],minn[1])+Min(tmp[tto][0]+minn[0],tmp[tto][1]+minn[1])+Min(cnt[tp][0]-tmp[tto][0],cnt[tp][1]-tmp[tto][1]));}else{ans = Max(ans,num-Min(cnt[tp][0],cnt[tp][1])-Min(maxn[0],maxn[1])+Min(tmp[tto][0]+maxn[0],tmp[tto][1]+maxn[1])+Min(cnt[tp][0]-tmp[tto][0],cnt[tp][1]-tmp[tto][1]));}ans = Max(ans,num-Min(cnt[tp][0],cnt[tp][1])+Min(tmp[tto][0]+(tto>n),tmp[tto][1]+(tto<=n))+Min(cnt[tp][0]-tmp[tto][0],cnt[tp][1]-tmp[tto][1]));ans = Max(ans,num-Min(cnt[tp][0],cnt[tp][1])+Min(tmp[tto][0],tmp[tto][1])+Min(cnt[tp][0]-tmp[tto][0]+(now>n),cnt[tp][1]-tmp[tto][1]+(now<=n)));}else{if(cnt[tp][0]>cnt[tp][1]){ans = Max(ans,num-Min(cnt[tp][0],cnt[tp][1])-Min(minn[0],minn[1])+Min(cnt[tp][0]+minn[0],cnt[tp][1]+minn[1]));}else{ans = Max(ans,num-Min(cnt[tp][0],cnt[tp][1])-Min(maxn[0],maxn[1])+Min(cnt[tp][0]+maxn[0],cnt[tp][1]+maxn[1]));}ans = Max(ans,num-Min(cnt[tp][0],cnt[tp][1])+Min(cnt[tp][0]+1,cnt[tp][1]));ans = Max(ans,num-Min(cnt[tp][0],cnt[tp][1])+Min(cnt[tp][0],cnt[tp][1]+1));}}
}
inline void solve(int T){minn[0] = 0,minn[1] = 0;maxn[0] = 0,maxn[1] = 0;for(int i=1;i<=n;++i) if(!dfn[a[i]]){cnt[a[i]][0] = cnt[a[i]][1] = 0;tarjan(a[i],a[i],a[i]);num += Min(cnt[a[i]][0],cnt[a[i]][1]);if(minn[0]-minn[1]>cnt[a[i]][0]-cnt[a[i]][1]){minn[0] = cnt[a[i]][0];minn[1] = cnt[a[i]][1];}if(maxn[0]-maxn[1]<cnt[a[i]][0]-cnt[a[i]][1]){maxn[0] = cnt[a[i]][0];maxn[1] = cnt[a[i]][1];}}for(int i=1;i<=n;++i) if(!dfn[b[i]+n]){cnt[b[i]+n][0] = cnt[b[i]+n][1] = 0;tarjan(b[i]+n,b[i]+n,b[i]+n);num += Min(cnt[b[i]+n][0],cnt[b[i]+n][1]);if(minn[0]-minn[1]>cnt[b[i]+n][0]-cnt[b[i]+n][1]){minn[0] = cnt[b[i]+n][0];minn[1] = cnt[b[i]+n][1];}if(maxn[0]-maxn[1]<cnt[b[i]+n][0]-cnt[b[i]+n][1]){maxn[0] = cnt[b[i]+n][0];maxn[1] = cnt[b[i]+n][1];}}ans = num;for(int i=1;i<=n;++i) if(!(tmp[a[i]][0]+tmp[a[i]][1])) get_ans(a[i],a[i]);for(int i=1;i<=n;++i) if(!(tmp[b[i]+n][0]+tmp[b[i+n]][1])) get_ans(b[i]+n,b[i]+n);printf("%d",ans);if(T){dtop = num = 0;for(int i=1;i<=n+n;++i){low[i] = dfn[i] = is_cut[i] = 0;cnt[i][0] = cnt[i][1] = 0;tmp[i][0] = tmp[i][1] = 0;}}
}
}// mainint main(){// freopen("in.in","r",stdin); // freopen("out.out","w",stdout);int T,ID; read(T,ID);while(T--){read(n);for(int i=1;i<=n;++i) read(a[i]);for(int i=1;i<=n;++i) read(b[i]);if(n==1){puts("1");continue;}for(int i=1;i<=n;++i){add(a[i],b[i]+n);add(b[i]+n,a[i]);}if(ID==0) Sub0 :: solve(T);else if(ID==1) Sub1 :: solve(T);else Sub2 :: solve(T);if(T){for(int i=1;i<=n+n;++i) head[i] = 0;edge_num = 0;putchar('\n');}}// fclose(stdin);// fclose(stdout);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/973247.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025云南曲靖市玉溪市一对一家教辅导测评排行榜:权威推荐高性价比选择

一、家教选择痛点凸显,两地学子急需优质辅导解决方案 在曲靖市麒麟区、沾益区、马龙区、宣威市、罗平县、富源县、师宗县、陆良县、会泽县,玉溪市红塔区、江川区、澄江市、通海县、华宁县、易门县、峨山彝族自治县、…

2026年盐城一对一补习机构权威推荐:靠谱辅导机构测评排行榜

盐城市小学、初中、高中家长在一对一家教选择中深陷困境:小学家长渴求靠谱教育机构夯实基础,却遇“试听课优质、正式课换师”的货不对板;初中家长筛选辅导培训平台时,常被“缴费不退”的霸王条款捆绑;高中家长为培…

2025高粱酒纯粮食酒推荐TOP10,纯粮固态发酵酱香浓郁回甘绵长

高粱酒作为中国白酒的核心品类,以高粱为主要原料的纯粮食酿造工艺,不仅承载着千年酿酒文化,更凭借醇厚的口感与自然的风味成为酒类消费市场的主流选择。不同香型的高粱酒在工艺、风味上各具特色,从酱香的醇厚绵长到…

2025内蒙古兴安盟锡林郭勒盟阿拉善盟一对一家教辅导测评排行榜:优质选择推荐

在兴安盟(乌兰浩特市、阿尔山市、科尔沁右翼前旗、科尔沁右翼中旗、扎赉特旗、突泉县)、锡林郭勒盟(锡林浩特市、二连浩特市、阿巴嘎旗、苏尼特左旗、苏尼特右旗、东乌珠穆沁旗、西乌珠穆沁旗、太仆寺旗、镶黄旗、正…

2025年煤矿用阻燃铠装光缆生产厂家权威推荐榜单:矿用铠装光缆/煤矿用光缆/矿用4芯光缆源头厂家精选

在煤矿智能化建设与安全生产要求不断提升的背景下,矿用阻燃铠装光缆以其卓越的机械防护性能和本质安全特性,正成为煤矿井下通信系统不可或缺的传输媒介。 煤矿井下环境复杂,存在瓦斯、煤尘等易燃易爆风险,对通信光…

玉树州一对一家教机构最新推荐,2026最新家教机构榜单:家长首选靠谱提分方案推荐

玉树市、杂多县、称多县、囊谦县、治多县、曲麻莱县的家长们,是不是总在为孩子的课外补习发愁?靠谱的玉树州一对一辅导机构哪家好?不同平台收费多少合理?如何避开“付费陪读”的坑?不管是结古大道、香达街周边的家…

回滚莫队模版

回滚莫队模版 题意 给定数列,查询 \(l\) 到 \(r\) 的众数。 思路 如果考虑暴力,我们需要一遍遍的遍历数列的数,然后求众数,但是这样效率太低了。 思考怎么优化,首先想到的线段树,但很容易发现这个众数一点都不好…

2025年拉袋离心机订制厂家权威推荐榜单:碟式离心机/卧螺离心机/活塞推料离心机源头厂家精选

在制药、化工等行业对固液分离技术要求不断提高的背景下,拉袋离心机凭借其自动化程度高、卸料效率优异的特点,正成为高端分离设备市场的重要选择。 据行业数据显示,2024年中国离心机市场规模已达156亿元,年均增长率…

Linux中: 通过编译安装的方式升级 OpenSSH 服务

Linux中: "通过编译安装的方式升级 OpenSSH 服务"OpenSSH 升级背景: 因为当前操作系统上的 OpenSSH 是通过包管理工具进行安装,因为低版本存在漏洞问题,但是官方仓库中没有最新的 OpenSSH 版本,所以此时…

纵观当代现状,70年代出生的人,可能别具一格

ECT-OS-JiuHuaShan/https://orcid.org/0009-0006-8591-1891对“70年代出生人群的别具一格”这一现象给出绝对确定性的因果分析。 历史相位的独特烙印 出生环境的因果特殊性 70年代出生者 = 成长于理想主义巅峰期(70-80…

#题解#洛谷 P4375 Out of Sorts G #离散化#

P4375 [USACO18OPEN] Out of Sorts G - 洛谷 分析注意到排序跟只跟数据的序相关,我们将原始数据离散化,并将数值更新为序不难注意到:每次moo只冒泡一次,对于每一个前缀子区间,会将较大的冒泡到末尾;由此不难想到…

hbase上如何导入python包

在 Hbase 上导入 Python 包(如 pandas、numpy、matplotlib 等)通常需要借助 Hadoop 的 YARN 环境 或 Hbase 的 HDFS 存储,因为 Hbase 本身是一个基于 HDFS 的分布式存储系统,其数据存储在 HDFS 上,而 Python 通常…

轻薄手机推荐:不止于轻,2025 旗舰体验榜 - 详解

轻薄手机推荐:不止于轻,2025 旗舰体验榜 - 详解2025-11-22 16:29 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; displa…

Git为什么要有submodule呢?

我们的项目中有一个子模块,所以导致经常更新master分支之后还需要对submodule进行一定的操作。所以我时常疑惑为什么会有这个东西呢?为什么一定要用子模块而不能把整个子模块加入我们的代码中呢? 其实主要解决的是这…

征程 6E/M 计算平台部署指南

1. 前言 本文旨在提供 征程 6E/M 计算平台的部署指南,将会从硬件、软件两部分进行介绍,本文整理了我们推荐的使用流程,和大家可能会用到的一些工具特性,以便于您更好地理解工具链。某个工具具体详细的使用说明,还…

2025年重庆废气收集处理机构权威推荐榜单:废气处理/废气治理/废气处理设备源头机构精选

在重庆工业绿色转型的浪潮中,专业的废气收集处理机构正凭借先进技术和服务经验,为制造业的可持续发展保驾护航。 随着环保要求的不断提高,重庆作为中国西部重要的工业基地,废气治理市场需求持续增长。据调研数据显…

详细介绍:第三章 FreeRTOS 任务相关 API 函数

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

数据库的安全与保护(下) - 实践

数据库的安全与保护(下) - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco&q…

2025年口碑好的江苏婚纱照/婚前影像/小众婚纱照/园林婚纱照/光影婚纱照/外景婚纱照/秀禾婚纱照/中式婚纱照/结婚照品牌推荐:弥素摄影领跑

摘要 江苏婚纱照行业在2025年持续蓬勃发展,随着新人对个性化、高品质拍摄需求的增长,小众高质感品牌逐渐成为市场新宠。本文基于行业数据和用户口碑,为您推荐排名前十的江苏婚纱照品牌,并提供详细对比,帮助您做出…