Codeforces 587D - Duff in Mafia(2-SAT+前后缀优化建图)
2-SAT hot tea。
首先一眼二分答案,我们二分答案 \(mid\),那么问题转化为,是否存在一个所有边权都 \(\le mid\) 的集合 \(S\),满足 \(S\) 中任意两条边的端点互不相同,并且没有选择的选择的边每种颜色的边两两之间的端点也互不相同。
乍一看这个问题看似无法解决。但不难发现每条边只有两种状态——选或不选,也就是说我们考虑将每条边拆成两个点 \(x_i\) 和 \(\lnot x_i\),分别表示边 \(i\) 被选入集合 \(S\) 中和边 \(i\) 没有被选入集合 \(S\) 然后跑 2-SAT,那么考虑这样建图:
- 对于权值 \(>mid\) 的边我们连一条 \(x_i\to\lnot x_i\) 的边,这样只要选择了 \(x_i\) 就必定会推出 \(\lnot x_i\) 也为真,也就导致了矛盾,因此这样连边就强制要求 \(\lnot x_i\) 必须为真。
- 对于两条有公共端点的边 \(i,j\),如果它们同时被纳入集合 \(S\) 中就会导致 \(S\) 中的边构不成匹配,因此如果 \(x_i\) 为真必然可以推出 \(\lnot x_j\) 为真,因此我们考虑连边 \(x_i\to\lnot x_j\),同理逆否命题 \(x_j\to\lnot x_i\)。
- 类似地,对于两条有公共端点且颜色相同的边 \(i,j\),如果它们同时不选,就会导致没选入 \(S\) 的边不合法,因此我们连边 \(\lnot x_i\to x_j,\lnot x_j\to x_i\)
这样暴力连边复杂度是 \(\mathcal O(m^2)\) 的,无法通过,考虑优化。以第二类边为例,我们考虑枚举两条边的公共点 \(i\),那么我们考虑将所有与 \(i\) 相连的边排成一列,设为 \(e_1,e_2,\cdots,e_k\),那么我们需要对于所有 \(1\le p,q\le k,p\ne q\),连边 \(x_p\to\lnot x_q\),不难发现这可以用前后缀优化建图优化,具体优化方案如下:

对于第三类边也按照同样方式优化一下即可。这样边数即可降到 \(\mathcal O(m)\) 级别。然后跑 tarjan,如果发现 \(\exists i\),\(x_i\) 与 \(\lnot x_i\) 在同一个强连通分量中说明 \(mid\) 不合法,否则由于 tarjan 强连通分量编号按照缩点后拓扑序,可通过 \(x_i\) 与 \(\lnot x_i\) 所在强连通分量大小关系判断 \(i\) 是否被选入集合 \(S\)。
时间复杂度 \(\mathcal O((n+m)\log n)\),为了减少常数可先把二、三类边建出来并保存一个备份,这样每次 check 时只需建一类边即可,不必每次二分都把整张图重新建出来。
const int MAXN=5e4;
const int MAXM=5e4;
const int MAXV=5e5;
const int MAXE=2e6;
int n,m,mx,ncnt=0;
struct edge{int u,v,c,t;} e[MAXM+5];
vector<int> g[MAXN+5];
vector<pii> col[MAXN+5];
int hd[MAXV+5],to[MAXE+5],nxt[MAXE+5],ec=0;
int _hd[MAXV+5],_ec=0;
void adde(int u,int v){to[++ec]=v;nxt[ec]=hd[u];hd[u]=ec;}
int dfn[MAXV+5],low[MAXV+5],stk[MAXV+5],tp=0;
int bel[MAXV+5],cmp=0,tim=0;bool vis[MAXV+5];
void tarjan(int x){
dfn[x]=low[x]=++tim;stk[++tp]=x;vis[x]=1;
for(int e=hd[x];e;e=nxt[e]){
int y=to[e];
if(!dfn[y]) tarjan(y),chkmin(low[x],low[y]);
else if(vis[y]) chkmin(low[x],dfn[y]);
}
if(dfn[x]==low[x]){
int o;cmp++;do{
o=stk[tp--];bel[o]=cmp;vis[o]=0;
} while(o^x);
}
}
bool check(int mid){
for(int i=1;i<=ncnt;i++) hd[i]=_hd[i];ec=_ec;
memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));tim=cmp=tp=0;
for(int i=1;i<=m;i++) if(e[i].t>mid) adde(i,i+m);
for(int i=1;i<=ncnt;i++) (!dfn[i]&&(tarjan(i),0));
for(int i=1;i<=m;i++) if(bel[i]==bel[i+m]) return 0;
return 1;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d%d%d",&e[i].u,&e[i].v,&e[i].c,&e[i].t);
chkmax(mx,e[i].t);g[e[i].u].pb(i);g[e[i].v].pb(i);
col[e[i].u].pb(mp(e[i].c,i));col[e[i].v].pb(mp(e[i].c,i));
} ncnt=m<<1;
for(int i=1;i<=n;i++) sort(col[i].begin(),col[i].end());
for(int i=1;i<=n;i++){
vector<int> pre(g[i].size()),suf(g[i].size());
for(int j=0;j<pre.size();j++) pre[j]=++ncnt;
for(int j=0;j<suf.size();j++) suf[j]=++ncnt;
for(int j=1;j<pre.size();j++) adde(pre[j-1],pre[j]);
for(int j=1;j<suf.size();j++) adde(suf[j],suf[j-1]);
for(int j=0;j<pre.size();j++) adde(g[i][j],pre[j]);
for(int j=0;j<suf.size();j++) adde(suf[j],g[i][j]+m);
for(int j=1;j<pre.size();j++) adde(pre[j-1],g[i][j]+m),adde(g[i][j],suf[j-1]);
}
for(int i=1;i<=n;i++){
for(int l=0,r;l<col[i].size();l=r){
r=l;while(r<col[i].size()&&col[i][r].fi==col[i][l].fi) ++r;
vector<int> pre(r-l),suf(r-l);
for(int j=0;j<pre.size();j++) pre[j]=++ncnt;
for(int j=0;j<suf.size();j++) suf[j]=++ncnt;
for(int j=1;j<pre.size();j++) adde(pre[j-1],pre[j]);
for(int j=1;j<suf.size();j++) adde(suf[j],suf[j-1]);
for(int j=0;j<pre.size();j++) adde(pre[j],col[i][j+l].se);
for(int j=0;j<suf.size();j++) adde(col[i][j+l].se+m,suf[j]);
for(int j=1;j<pre.size();j++) adde(col[i][j-1+l].se+m,pre[j]),adde(suf[j],col[i][j-1+l].se);
}
}
for(int i=1;i<=ncnt;i++) _hd[i]=hd[i];_ec=ec;
int l=0,r=mx,p=-1;
while(l<=r){
int mid=l+r>>1;
if(check(mid)) p=mid,r=mid-1;
else l=mid+1;
} if(!~p) puts("No");
else{
printf("Yes\n%d ",p);check(p);vector<int> vec;
for(int i=1;i<=m;i++) if(bel[i]<bel[i+m]) vec.pb(i);
printf("%d\n",vec.size());for(int x:vec) printf("%d ",x);
}
return 0;
}
Codeforces 587D - Duff in Mafia(2-SAT+前后缀优化建图)的更多相关文章
- 洛谷P3783 [SDOI2017]天才黑客(前后缀优化建图+虚树+最短路)
题面 传送门 题解 去看\(shadowice\)巨巨写得前后缀优化建图吧 话说我似乎连线段树优化建图的做法都不会 //minamoto #include<bits/stdc++.h> # ...
- 【SDOI2017】天才黑客(前后缀优化建图 & 最短路)
Description 给定一张有向图,\(n\) 个点,\(m\) 条边.第 \(i\) 条边上有一个边权 \(c_i\),以及一个字符串 \(s_i\). 其中字符串 \(s_1, s_2, \c ...
- 洛谷 P3783 - [SDOI2017]天才黑客(前后缀优化建图)
题面传送门 神仙题一道. 首先注意到这里的贡献涉及到边的顺序,并且只与相邻的边是什么有关,因此不难想到一个做法--边转点,点转边,具体来说对于每条边 \(e\),我们将其拆成两个点 \(in_e,ou ...
- Codeforces.1045A.Last chance(最大流ISAP 线段树优化建图)
题目链接 \(Description\) 你需要用给定的\(n\)个武器摧毁\(m\)架飞船中的某一些.每架飞船需要被摧毁恰好一次. 武器共三种:1.可以在给定的集合中摧毁一架飞船:2.可以摧毁区间\ ...
- UESTC30-最短路-Floyd最短路、spfa+链式前向星建图
最短路 Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) 在每年的校赛里,所有进入决赛的同 ...
- [Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路)
[Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路) 题面 有n个空心物品,每个物品有外部体积\(out_i\)和内部体积\(in_i\),如果\(in_i& ...
- 【CF587D】Duff in Mafia 二分+前缀优化建图+2-SAT
[CF587D]Duff in Mafia 题意:给你一张n个点m条边的无向图,边有颜色和边权.你要从中删去一些边,满足: 1.任意两条删掉的边没有公共的顶点.2.任意两条剩余的.颜色相同的边没有公共 ...
- 区间->点,点->区间,线段树优化建图+dijstra Codeforces Round #406 (Div. 2) D
http://codeforces.com/contest/787/problem/D 题目大意:有n个点,三种有向边,这三种有向边一共加在一起有m个,然后起点是s,问,从s到所有点的最短路是多少? ...
- CodeForces 786B Legacy(线段树优化建图+最短路)
[题目链接] http://codeforces.com/problemset/problem/786/B [题目大意] 给出一些星球,现在有一些传送枪,可以从一个星球到另一个星球, 从一个星球到另一 ...
随机推荐
- javascript高级程序设计第三版书摘
在HTML 中使用JavaScript <script>元素 在使用<script>元素嵌入 JavaScript 代码时,只须为<script>指定 type 属 ...
- SLAM名词介绍
gauge freedom:测量自由度 degrees-of-freedom(DoF) 自由度 wide-baseline matches:宽基线匹配 宽基线匹配:从描绘同一场景的两个或多个图像中建立 ...
- .net 5.0 ref文件夹的作用
ref目录里的dll是一个名为参考组件的东西,微软MSDN给的解释是 参考组件是一种特殊类型的程序集,仅包含表示库的公共API面所需的最小元数据数量.它们包括用于在构建工具中引用程序集时重要的所有成员 ...
- time_formatter攻防世界学习
time_formatter 前言:这题说实话分析量蛮大的,首先是程序内壁比较绕,而且调用了之前许多没有见到的函数---如snprintf_che,以及strsup(好像打错了),getegid(), ...
- 零基础入门C/C++实现你的浪漫表白:浪漫流星雨表白程序
想要讨女朋友欢心也巩固自己所学的知识,各位小伙伴有自己的想法了吗?准备好想要怎样实施了吗?有什么美好的计划了吗?如果没有的话那么别慌,我知道,在座的各位肯定都是有自己的心仪的姑娘,那么今天就教大家一招 ...
- 公众号H5页面接入微信登录流程
公众号H5页面接入微信登录流程 源码地址 https://gitee.com/szxio/h5_weixin 起步 首先创建一个项目,我们采用uni-app来作为我们的前端框架 环境安装 全局安装vu ...
- C# 如何将日期格式化ISO8601模式
类似于这样的时间戳格式:预计来访时间,时间参数需满足ISO8601格式:yyyy-MM-ddTHH:mm:ss+当前时区,例如北京时间:2018-07-26T15:00:00 + 08:00 stri ...
- sort-list leetcode C++
Sort a linked list in O(n log n) time using constant space complexity. C++ /** * Definition for sing ...
- Redis源码分析(intset)
源码版本:4.0.1 源码位置: intset.h:数据结构的定义 intset.c:创建.增删等操作实现 1. 整数集合简介 intset是Redis内存数据结构之一,和之前的 sds. skipl ...
- Java测试开发--Spring Tools Suite (STS) 简介(一)
sts是一个定制版的Eclipse,专为Spring开发定制的,方便创建调试运行维护Spring应用. 官网下载之后,可以看到一个sts-bundle,里面有三个文件夹,一个法律信息,一个tc Ser ...