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 [题目大意] 给出一些星球,现在有一些传送枪,可以从一个星球到另一个星球, 从一个星球到另一 ...
随机推荐
- c语言中for循环 和嵌套for循环
for循环:for( ; ; )里面是bai3个语句,两个分号.第一个语句是开始前执行,第二个语句是判断真假,如果真,就执行后面(大括号内)的代码.第三个语句是每次执行完毕后执行的东西,通常第三个语句 ...
- vue 解决axios请求出现前端跨域问题
vue 解决axios请求出现前端跨域问题 最近在写纯前端的vue项目的时候,碰到了axios请求本机的资源的时候,出现了访问报404的问题.这就让我很难受.查询了资料原来是跨域的问题. 在正常开发中 ...
- vue3.x异步组件
在大型应用中,我们可能需要将应用分割成小一些的代码块,并且只在需要的时候才从服务器加载一个模块 vue2.x 曾经简单的异步组件 components: { AsyncComponent: () =& ...
- 什么是Sprint计划?
Sprint 计划是Scrum框架中的一个事件,团队将确定他们将在冲刺期间处理的产品积压项目,并讨论他们完成这些产品积压项目的初始计划. 团队可能会发现建立冲刺目标很有帮助,并以此为基础确定他们在冲刺 ...
- LeetCode:动态规划
动态规划 动态规划永远的神 这部分主要是学习了 labuladong 公众号中对于动态规划的讲解 刷了些 leetcode 题,在此做一些记录,不然没几天就忘光光了 题目 这部分内容直接上题目了,解题 ...
- LeetCode:堆专题
堆专题 参考了力扣加加对与堆专题的讲解,刷了些 leetcode 题,在此做一些记录,不然没几天就忘光光了 力扣加加-堆专题(上) 力扣加加-堆专题(下) 总结 优先队列 // 1.java中有优先队 ...
- C++ Boost signal2信号/插槽
#include "stdafx.h" #include "boost/signals2.hpp" #include "boost/bind.hpp& ...
- 大牛针对零基础入门c语言详解指针(超详细)
C语言指针说难不难但是说容易又是最容易出错的地方,因此不管是你要做什么只要用到C指针你就跳不过,今天咱们就以 十九个例子来给大家简单的分析一下指针的应用,最后会有C语言视频资料提供给大家更加深入的参考 ...
- HITS算法简介
1.算法名称 超文本敏感标题搜索 (Hyperlink-Induced Topic Search) 2.算法背景 HITS 算法是由康奈尔大学的Jon Kleinberg 博士于1997 年首先提出的 ...
- 第k短路(Dijkstra & A*)
最短路,即第1短路有很多种求法,SPFA,Dijkstra等,但第k短路怎么求呢?其实也是基于Dijkstra:因为Dijkstra用的是堆优化,这样保证每次弹出来的都是最小值,只是求最短路只是弹出一 ...