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. Linux中使用dd制作文件的.img

    dd if=/dev/zero of=new_img.img bs=1M count=20   //生成20M的文件,bs块的大小,count块的数量 mkfs.ext3 new_img.img  / ...

  2. VS2015+OpenCV+Qt

    VS2015+OpenCV+Qt 01.OpenCV 下载 进入官网链接: https://opencv.org,下载所需要的版本: 下载完成后直接双击,选择解压路径,解压到响应的文件夹中: 若之后需 ...

  3. 正则表达式: NFA引擎匹配原理

    NFA引擎匹配原理 1       为什么要了解引擎匹配原理 一个个音符杂乱无章的组合在一起,弹奏出的或许就是噪音,同样的音符经过作曲家的手,就可以谱出非常动听的乐曲,一个演奏者同样可以照着乐谱奏出动 ...

  4. Noip模拟12 2021.7.12

    T1 interval 亏得昨天晚上改掉了T3并且理解了单调栈,今天一扫这题目就知道要用啥了. 先预处理出以a[i]为最大值的最大左右区间.然后再将a[i]取%!!!是的,要不然会影响单调栈的使用.. ...

  5. linux Segmentation faults 段错误详解

    什么是段错误 下面是来自 Answers.com 的定义: A segmentation fault (often shortened to segfault) is a particular err ...

  6. python读取、写入txt文本内容

    转载:https://blog.csdn.net/qq_37828488/article/details/100024924 python常用的读取文件函数有三种read().readline().r ...

  7. 求1+2+3...+n 牛客网 剑指Offer

    求1+2+3...+n 牛客网 剑指Offer 题目描述 求1+2+3+...+n,要求不能使用乘除法.for.while.if.else.switch.case等关键字及条件判断语句(A?B:C). ...

  8. cm0 逆向分析

    目录 cm0 逆向分析 前言 Strings工具复习 String工具使用说明 Strings工具解cm0题 cm0 逆向分析 前言 Emmmmm,我假装你看到这里已经学过了我的<恶意代码分析实 ...

  9. Dubbo之负载均衡、并发控制、延迟暴露、连接控制

    1.并发控制 dubbo服务端和消费端都做了并发控制,分别在配置中有相应的对应配置: 服务端:executes服务提供者每服务每方法最大可并行执行请求数,控制并发数量:actives每服务消费者每服务 ...

  10. 基于Dapr的 Azure 容器应用

    微软在 Ignite 2021 大会上发布了预览版的Azure Container Apps,这是一个完全托管的无服务器容器运行时间,用于大规模构建和运行现代应用程序.从2021 年 11 月 2 日 ...