[Tricks-00003]CF1989F 套路叠加,高级分治

news/2024/11/16 8:35:27/文章来源:https://www.cnblogs.com/maihe/p/18546657

先说一个简单问题:给定一个 \(n\times m\) 的黑白网格图,每次可以将一行或者一列染成同一种色,判断是否能到达?

经典做法:倒过来考虑,每次将颜色全相同或为 * 的一行全染成 *,判断是否可以将这张图染成全 *。经典网格图转二分图,如果 \(s_{i,j}='W'\) 则将 \(i\)\(j'\) 连一条有向边,否则 \(j'\)\(i\) 连。每次相当于将一个没有出度或入度的点对应的边都删掉,判断是否能把所有边删空。容易发现等价于判断是否存在强连通分量,如果是 DAG,则直接按拓扑序取即可,否则随便找一个 SCC,里面点永远动不了。

不过这个题有额外操作方法,保证了每个 SCC 都也能操作成功,那么这个代价怎么算呢?

upd:不是哥们我读错题了,,,当时这里卡住了以为是个很难的问题,现在发现,它的题意指的是,同时染的格子的颜色可以从这次染这行的和这列的里面随便选一个,不过不能凭空制造!因此本题应该换个角度这样理解:咕咕咕

现在有了这个结论,那么我们只需要求出每个时刻的 SCC 状态即可!!!

受到一些可能是 QOJ 上的经典题的启发,我们想到了分治!不过类似连通性这种直接做分治,会遇到一些很大的问题。我比如把 \(time\leq mid\) 的所有边拿出来跑 SCC,那么现在会产生一个缩点之后是 DAG 的有向图,可是我这些 DAG 边究竟应该放哪里呢?我之后做右半边的时候点是用缩完之后还是之前的呢???

所以接下来我们就要明确一下这个常见套路。我们对每条边求出的是,它在第几时刻之后"完成使命"了,也就是说,相连的两个点归到了同一个 SCC。这样,我最后求每个时刻的 SCC 时,只要把挂在这个时刻上的所有边拉出来,缩个并查集就好了。因此,我们可以用 solve(l,r,vector<int>g) 来表示一次分治,要去将 \(g\) 里面所有边得到它们对应的时刻。当然,有可能完成不了使命,我们就将其设为 \(q+1\),不是大问题。当然,每条边的完成时刻一定不早于出现时刻。所以何时加什么边就很明确了:

先得到一个 \(mid\)。将 \(g\) 中所有 \(time\leq mid\) 的边拉出来跑 SCC,得到一堆强连通块,这样可以求出 \(g\) 中每条边应该归到左,还是右,亦或直接扔掉。具体地,对一个 \(\leq mid\) 的边,如果两点已经属于一个 SCC 了,就归到左边,否则归到右边;\(>mid\) 的边,如果两点已经属于了,就没用可以扔了,否则归到右边,接下来继续递归即可。

看起来很对,不过写代码的时候会产生这样一个问题:用缩前还是缩后的点来着?其实很容易想到肯定是用缩后的点的,不过加入的时间要注意一下,应该是先递归处理左半边,然后把这次的 SCC 缩点做好(可以再用个并查集维护),最后处理右半边。不难做到 \(O(n+q\log q)\)。如果实现地不精细多个 log 也无所谓,只要不写 set 常数应该还好。

代码:

#include<bits/stdc++.h>
using namespace std;
int uu[200005],vv[200005],cx[200005],N;
vector<int>g[400005];
int dfn[400005],low[400005],st[400005],vist[400005];
int col[400005],t1=0,t2=0;
void tarjan(int x){dfn[x]=low[x]=++t1;st[++t2]=x,vist[x]=1;for(auto cu:g[x]){if(!dfn[cu]){tarjan(cu);low[x]=min(low[x],low[cu]);}else if(vist[cu]){low[x]=min(low[x],dfn[cu]);}}if(dfn[x]!=low[x])return;int pp;do{pp=st[t2--];vist[pp]=0;col[pp]=x;}while(pp!=x);
}
int ff[400005];
int findff(int x){return x==ff[x]?x:ff[x]=findff(ff[x]);
}
void solve(int l,int r,vector<int>gg){if(l==r){for(auto d:gg)cx[d]=l;return;}int mid=(l+r)>>1;vector<int>se;for(auto d:gg){int U=findff(uu[d]),V=findff(vv[d]);dfn[U]=low[U]=col[U]=vist[U]=0;dfn[V]=low[V]=col[V]=vist[V]=0;if(d<=mid){se.emplace_back(U);se.emplace_back(V);g[U].emplace_back(V);}}sort(se.begin(),se.end());se.resize(unique(se.begin(),se.end())-se.begin());t1=t2=0;for(auto x:se)if(!dfn[x]){tarjan(x);}vector<int>g1,g2;for(auto d:gg){int U=ff[uu[d]],V=ff[vv[d]];if(d<=mid){if(col[U]==col[V])g1.emplace_back(d);else g2.emplace_back(d);}else{if(col[U]!=col[V]||!col[U]||!col[V])g2.emplace_back(d);}}vector<pair<int,int>>v;for(auto x:se){g[x].clear();v.emplace_back(x,col[x]);}solve(l,mid,g1);for(auto pi:v){int fx=findff(pi.first),fy=findff(pi.second);if(fx!=fy)ff[fx]=fy;}solve(mid+1,r,g2);
}
int fa[400005],cnt[400005];
int findfather(int x){return x==fa[x]?x:fa[x]=findfather(fa[x]);
}
vector<int>v2[200005];
long long f(int x){return x==1?0:1ll*x*x;
}
int main(){int n,m,q;scanf("%d%d%d",&n,&m,&q);N=n+m;for(int i=1;i<=q;++i){int u,v;char op[15];scanf("%d%d%s",&u,&v,op+1);int U=u,V=n+v;if(op[1]=='B')swap(U,V);uu[i]=U,vv[i]=V;}vector<int>vc;for(int i=1;i<=q;++i)vc.emplace_back(i);for(int i=1;i<=N;++i)ff[i]=i;solve(1,q+1,vc);for(int i=1;i<=N;++i)fa[i]=i,cnt[i]=1;for(int i=1;i<=q;++i){if(cx[i]&&cx[i]<=q)v2[cx[i]].emplace_back(i);}long long ans=0;for(int i=1;i<=q;++i){for(auto d:v2[i]){int fu=findfather(uu[d]),fv=findfather(vv[d]);if(fu!=fv){fa[fu]=fv;ans=ans-f(cnt[fu])-f(cnt[fv]);ans=ans+f(cnt[fv]+=cnt[fu]);}}printf("%lld\n",ans);}return 0;
}

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

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

相关文章

NOIP2024 前集训:NOIP2024加赛 5

前言music 《浮光》看指尖拨响蝴蝶 扇动一场离别我推开无声岁月 续梦一页你我只是打个照面 可曾有过誓约走进熟悉却 陌生的思念啊……啊……你的眼眸 装满了时间你的身后 拥故事成篇此生如梦 愿细数流年与你同写 沧海桑田浮光掠影 重山彩云间你的伏线 穿越千百年人生不过 恍惚三…

读数据质量管理:数据可靠性与数据质量问题解决之道05数据标准化

数据标准化1. 批处理 1.1. 批处理在一段时间内收集数据,然后将大量数据“批处理”在离散的数据包中 1.2. 直到20世纪10年代中期,批处理都是处理分析型数据最常用的方法 1.3. 批处理比流处理要便宜得多,即使是对时间要求最苛刻的处理需求也足以满足 1.4. 批处理是经过时间考验…

基于C#开源、功能强大、灵活的跨平台开发框架 - Uno Platform

前言 今天大姚给大家分享一个基于C#开源、功能强大、灵活的跨平台开发框架:Uno Platform。通过 Uno Platform,开发者可以利用单一代码库实现多平台兼容,极大地提高了开发效率和代码复用性。项目介绍 Uno Platform是一个基于C#开源、功能强大、灵活的跨平台开发框架,用于快速…

chrony配置/释义

[root@c7-1 ~]# cat /etc/centos-release CentOS Linux release 7.9.2009 (Core)[root@c7-1 ~]# yum -y install chrony [root@c7-1 ~]# vim /etc/chrony.conf # 自带 server 0.centos.pool.ntp.org iburst server 1.centos.pool.ntp.org iburst server 2.centos.pool.ntp…

WPF 打开资源管理器且选中某个文件

本文将和大家介绍如何在 Windows 系统上使用 SHOpenFolderAndSelectItems 方法打开资源管理器且选中给定的文件打开资源管理器且选中某个文件可以使用 cmd 调用 explorer 带上 select 参数,如下面命令行所示 explorer.exe /select,"C:\Folder\file.txt"但有很多情况…

Virtual Box 虚拟机扩容

Virtual Box 虚拟机扩容 扩容有风险,有可能导致磁盘损坏,系统不可用。 需要使用的工具 gparted GParted -- A free application for graphically managing disk device partitions 步骤图解 1.扩大虚拟硬盘的容量2.加载分区工具执行分区操作3.扩展逻辑卷 要扩大 / 分区的空间…

RealCustom:缩小真实文本词的范围,实现实时开放域文本到图像的定制

RealCustom:缩小真实文本词的范围,实现实时开放域文本到图像的定制文本到图像定制旨在为给定的主题合成文本驱动的图像,最近彻底改变了内容创作。现有的作品遵循伪词范式,即将给定的主题表示为伪词,然后将其与给定的文本组合在一起。然而,伪词与给定文本固有的纠缠扩散范…

网站f12代码怎么修改,掌握网站F12调试工具的使用技巧

打开F12开发者工具:在浏览器中打开您需要调试的网页,按下F12键或右键点击页面任意位置选择“检查”(Inspect),即可打开开发者工具。选择Elements面板:在开发者工具顶部的选项卡中,选择“Elements”面板。这里显示了当前页面的HTML结构。查找目标元素:使用鼠标悬停在页面…

织梦手机网站模板修改,如何在织梦CMS中修改手机网站模板

织梦CMS(DedeCMS)支持手机网站模板的自定义,通过以下步骤可以轻松修改手机网站模板:登录后台:打开浏览器,输入织梦CMS的后台地址,使用管理员账号登录。进入模板管理:在后台左侧菜单栏中选择“模板” -> “默认模板管理”。 选择“手机模板”选项卡,查看当前使用的手…

网站开源代码修改,如何在本地开发环境中修改网站开源代码

修改网站开源代码可以定制网站的功能和设计。以下是修改网站开源代码的步骤:克隆代码仓库:使用Git或其他版本控制工具克隆网站的开源代码仓库。 例如:git clone https://github.com/username/repository.git cd repository安装依赖:根据项目文档安装所需的依赖库。 例如,使…

Codeforces Round 985 div2 个人题解(A~E)

Codeforces Round 985 div2 个人题解(A~E) Dashboard - Codeforces Round 987 (Div. 2) - Codeforces 火车头 #include <bits/stdc++.h>using namespace std;#define ft first #define sd second#define yes cout << "yes\n" #define no cout << &…

CTF/9/pwnerTool,一个适用于CTF中自动对Pwn题目文件进行信息收集,并且生成基础做题py文件的Pwn工具

CTF中自动对Pwn题目文件进行信息收集,并且生成基础做题py文件的Pwn工具,适用于Ubuntu 随手写的,写的不好请轻喷. 一个用于ctf对Pwn题目文件进行信息收集,打包了检查文件类型、检查类型保护、新建py文件、寻找传参工具的过程。 同时可以修补题目给出的动态库和libc文件保证本…