Codeforces 题面传送门 & 洛谷题面传送门

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+前后缀优化建图)的更多相关文章

  1. 洛谷P3783 [SDOI2017]天才黑客(前后缀优化建图+虚树+最短路)

    题面 传送门 题解 去看\(shadowice\)巨巨写得前后缀优化建图吧 话说我似乎连线段树优化建图的做法都不会 //minamoto #include<bits/stdc++.h> # ...

  2. 【SDOI2017】天才黑客(前后缀优化建图 & 最短路)

    Description 给定一张有向图,\(n\) 个点,\(m\) 条边.第 \(i\) 条边上有一个边权 \(c_i\),以及一个字符串 \(s_i\). 其中字符串 \(s_1, s_2, \c ...

  3. 洛谷 P3783 - [SDOI2017]天才黑客(前后缀优化建图)

    题面传送门 神仙题一道. 首先注意到这里的贡献涉及到边的顺序,并且只与相邻的边是什么有关,因此不难想到一个做法--边转点,点转边,具体来说对于每条边 \(e\),我们将其拆成两个点 \(in_e,ou ...

  4. Codeforces.1045A.Last chance(最大流ISAP 线段树优化建图)

    题目链接 \(Description\) 你需要用给定的\(n\)个武器摧毁\(m\)架飞船中的某一些.每架飞船需要被摧毁恰好一次. 武器共三种:1.可以在给定的集合中摧毁一架飞船:2.可以摧毁区间\ ...

  5. UESTC30-最短路-Floyd最短路、spfa+链式前向星建图

    最短路 Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) 在每年的校赛里,所有进入决赛的同 ...

  6. [Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路)

    [Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路) 题面 有n个空心物品,每个物品有外部体积\(out_i\)和内部体积\(in_i\),如果\(in_i& ...

  7. 【CF587D】Duff in Mafia 二分+前缀优化建图+2-SAT

    [CF587D]Duff in Mafia 题意:给你一张n个点m条边的无向图,边有颜色和边权.你要从中删去一些边,满足: 1.任意两条删掉的边没有公共的顶点.2.任意两条剩余的.颜色相同的边没有公共 ...

  8. 区间->点,点->区间,线段树优化建图+dijstra Codeforces Round #406 (Div. 2) D

    http://codeforces.com/contest/787/problem/D 题目大意:有n个点,三种有向边,这三种有向边一共加在一起有m个,然后起点是s,问,从s到所有点的最短路是多少? ...

  9. CodeForces 786B Legacy(线段树优化建图+最短路)

    [题目链接] http://codeforces.com/problemset/problem/786/B [题目大意] 给出一些星球,现在有一些传送枪,可以从一个星球到另一个星球, 从一个星球到另一 ...

随机推荐

  1. 【UE4 C++ 基础知识】<1> UPROPERTY宏、属性说明符、元数据说明符

    属性声明 属性使用标准的C++变量语法声明,前面用UPROPERTY宏来定义属性元数据和变量说明符. UPROPERTY([specifier, specifier, ...], [meta(key= ...

  2. 回应:Alpha深度评测

    零.说明 本篇博客是针对博客沉舟侧畔千帆过,病树前头万木春--对[题士]产品的深度测评与解析的回应,用以说明『题士』开发团队的观点.改进计划等 感谢HansBug.CookieLau助教及各位老师.测 ...

  3. 并发编程从零开始(八)-ConcurrentHashMap

    并发编程从零开始(八)-ConcurrentHashMap 5.5 ConcurrentHashMap HashMap通常的实现方式是"数组+链表",这种方式被称为"拉链 ...

  4. 零基础玩转C语言单链表

    下图为最一简单链表的示意图: 第 0 个结点称为头结点,它存放有第一个结点的首地址,它没有数据,只是一个指针变量.以下的每个结点都分为两个域,一个是数据域,存放各种实际的数据,如学号 num,姓名 n ...

  5. Machine learning(4-Linear Regression with multiple variables )

    1.Multiple features So what the form of the hypothesis should be ? For convenience, define x0=1 At t ...

  6. 『学了就忘』Linux基础 — 9、虚拟机中快照的使用

    目录 1.快照的含义 2.快照的使用 步骤一:创建拍摄快照 步骤二:填写快照信息并创建 步骤三:查看快照 步骤四:操作快照 3.管理虚拟机小技巧 4.关于快照说明 快照和克隆是VMware中两个非常实 ...

  7. 神经网络 感知机 Perceptron python实现

    import numpy as np import matplotlib.pyplot as plt import math def create_data(w1=3,w2=-7,b=4,seed=1 ...

  8. Luogu P1563 [NOIp2016提高组]玩具谜题 | 模拟

    题目链接 纯模拟题,没啥好说的,就是要判断地方有点多,一定要注意细节. #include<iostream> #include<cstdio> #include<fstr ...

  9. vue mvc与mvvm

    一.什么是MVVM? MVVM是Model-View-ViewModel的缩写.MVVM是一种设计思想.Model 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑:View 代表UI ...

  10. Swift-技巧(四)设置照片尺寸和格式

    摘要 平时实现拍照功能时,都是网上一通搜索,整体复制粘贴,自称无脑实现.但是当要求照片是不同的尺寸和格式( JPEG)时,就费力搞照片.其实在设置拍照时,就可以直接设置照片的尺寸和格式,用直接的方法来 ...