【CF587D】Duff in Mafia 二分+前缀优化建图+2-SAT
【CF587D】Duff in Mafia
题意:给你一张n个点m条边的无向图,边有颜色和边权。你要从中删去一些边,满足:
1.任意两条删掉的边没有公共的顶点。
2.任意两条剩余的、颜色相同的边没有公共的顶点。
3.删去的边的边权最大值最小。
求这个最小值,并输出方案。
$n,m\le 5\times 10^4$
题解:首先二分答案。我们二分删去边权的最大值mid,则所有>mid的边都要保留,其余的可以保留也可以删去。因为每条边有删或不删两种状态,所以容易转化为2-SAT模型。于是题中条件可以转化成若干个形如这样的约束:在一个边集中,最多有一条边被删(不删)。
这是一个经典的2-SAT模型,有一个常用办法:前缀优化建图。
我们把集合中的元素排成一排,然后新建两排节点,第一排的第i个点代表在前i个元素中有一个元素被选择了,第二排的第i个点代表前i个元素中一个被选的都没有。假如某个元素选的状态是$x_i$,不选的状态是$x_i'$,对应的前缀分别是$S_i$和$S_i'$,那么:
前缀的传递:$S_{i-1}->S_i$,$S_i'->S_{i-1}'$
用当前元素更新当前前缀:$x_i->S_i,S_i'->x_i'$
用前缀来约束当前元素:$S_{i-1}->x_i',x_i->S_{i-1}'$
记住,一共6条边哦!
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#define A(_) (((_)<<1)-1)
#define B(_) ((_)<<1)
using namespace std;
const int maxn=500010;
int n,m,mid,tot,cnt,top,sum;
int to[2000010],nxt[2000010],head[maxn],dep[maxn],q[maxn],bel[maxn],low[maxn],sta[maxn],ins[maxn];
vector<int> v[maxn];
vector<int>::iterator it;
struct edge
{
int a,b,c,d;
}p[maxn];
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+(gc^'0'),gc=getchar();
return ret*f;
}
inline void add(int a,int b)
{
to[cnt]=b,nxt[cnt]=head[a],head[a]=cnt++;
}
bool cmp(const int &a,const int &b)
{
return p[a].c<p[b].c;
}
inline void work1()
{
int i;
for(i=1;i<=q[0];i++)
{
add(A(q[i]),A(i)+tot),add(B(i)+tot,B(q[i]));
if(i!=1)
{
add(A(i-1)+tot,A(i)+tot),add(B(i)+tot,B(i-1)+tot);
add(A(i-1)+tot,B(q[i])),add(A(q[i]),B(i-1)+tot);
}
}
tot+=q[0]<<1,q[0]=0;
}
inline void work2()
{
int i;
for(i=1;i<=q[0];i++)
{
add(B(q[i]),B(i)+tot),add(A(i)+tot,A(q[i]));
if(i!=1)
{
add(B(i-1)+tot,B(i)+tot),add(A(i)+tot,A(i-1)+tot);
add(B(i-1)+tot,A(q[i])),add(B(q[i]),A(i-1)+tot);
}
}
tot+=q[0]<<1,q[0]=0;
}
void tarjan(int x)
{
dep[x]=low[x]=++dep[0],ins[x]=1,sta[++top]=x;
for(int i=head[x];i!=-1;i=nxt[i])
{
if(!dep[to[i]]) tarjan(to[i]),low[x]=min(low[x],low[to[i]]);
else if(ins[to[i]]) low[x]=min(low[x],dep[to[i]]);
}
if(dep[x]==low[x])
{
sum++;
int t;
do
{
t=sta[top--],ins[t]=0,bel[t]=sum;
}while(t!=x);
}
}
inline bool check()
{
int i;
tot=m<<1,cnt=0,memset(head,-1,sizeof(head));
for(i=1;i<=m;i++) if(p[i].d>mid) add(B(i),A(i));
for(i=1;i<=n;i++)
{
for(it=v[i].begin();it!=v[i].end();it++)
{
if(q[0]&&p[*it].c!=p[q[q[0]]].c) work1();
q[++q[0]]=*it;
}
work1();
for(it=v[i].begin();it!=v[i].end();it++) q[++q[0]]=*it;
work2();
}
memset(dep,0,sizeof(dep)),sum=0;
for(i=1;i<=tot;i++) if(!dep[i]) tarjan(i);
for(i=1;i<=tot;i+=2) if(bel[i]==bel[i+1]) return 0;
return 1;
}
int main()
{
//freopen("cf587D.in","r",stdin);
n=rd(),m=rd();
int i,l=0,r=0,flag=0;
for(i=1;i<=m;i++)
{
p[i].a=rd(),p[i].b=rd(),p[i].c=rd(),p[i].d=rd(),r=max(r,p[i].d+1);
v[p[i].a].push_back(i),v[p[i].b].push_back(i);
}
for(i=1;i<=n;i++) sort(v[i].begin(),v[i].end(),cmp);
while(l<r)
{
mid=(l+r)>>1;
if(check()) r=mid,flag=1;
else l=mid+1;
}
if(!flag)
{
puts("No");
return 0;
}
mid=r,check();
tot=0;
for(i=1;i<=m;i++) if(bel[A(i)]>bel[B(i)]) q[++tot]=i;
printf("Yes\n%d %d\n",r,tot);
for(i=1;i<=tot;i++) printf("%d ",q[i]);
return 0;
}
【CF587D】Duff in Mafia 二分+前缀优化建图+2-SAT的更多相关文章
- CF1007D. Ants(树链剖分+线段树+2-SAT及前缀优化建图)
题目链接 https://codeforces.com/problemset/problem/1007/D 题解 其实这道题本身还是挺简单的,这里只是记录一下 2-SAT 的前缀优化建图的相关内容. ...
- [SDOI2017]天才黑客[最短路、前缀优化建图]
题意 一个 \(n\) 点 \(m\) 边的有向图,还有一棵 \(k\) 个节点的 trie ,每条边上有一个字符串,可以用 trie 的根到某个节点的路径来表示.每经过一条边,当前携带的字符串就会变 ...
- BZOJ.3495.[PA2010]Riddle(2-SAT 前缀优化建图)
题目链接 每个城市要么建首都要么不建,考虑2-SAT 这样一个国家内城市两两连边是很显然的,但是边数为O(n^2) 每个国家中仅有一个建首都,考虑新建前缀S[i]=1/0这2n个点表示当前国家的[1, ...
- Codeforces 587D - Duff in Mafia(2-SAT+前后缀优化建图)
Codeforces 题面传送门 & 洛谷题面传送门 2-SAT hot tea. 首先一眼二分答案,我们二分答案 \(mid\),那么问题转化为,是否存在一个所有边权都 \(\le mid\ ...
- 【ARC069F】Flags 2-sat+线段树优化建图+二分
Description 数轴上有 n 个旗子,第 ii 个可以插在坐标 xi或者 yi,最大化两两旗子之间的最小距离. Input 第一行一个整数 N. 接下来 N 行每行两个整数 xi, ...
- 4.15 省选模拟赛 编码 trie树 前缀和优化建图 2-sat
好题 np. 对于20分 显然可以爆搜. 对于50分 可以发现每个字符串上的问号要么是0,要么是1.考虑枚举一个字符串当前是0还是1 这会和其他字符串产生矛盾. 所以容易 发现这是一个2-sat问题. ...
- [十二省联考2019]字符串问题——后缀自动机+parent树优化建图+拓扑序DP+倍增
题目链接: [十二省联考2019]字符串问题 首先考虑最暴力的做法就是对于每个$B$串存一下它是哪些$A$串的前缀,然后按每组支配关系连边,做一遍拓扑序DP即可. 但即使忽略判断前缀的时间,光是连边的 ...
- 【bzoj5017】[Snoi2017]炸弹 线段树优化建图+Tarjan+拓扑排序
题目描述 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆. 现在 ...
- [Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路)
[Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路) 题面 有n个空心物品,每个物品有外部体积\(out_i\)和内部体积\(in_i\),如果\(in_i& ...
随机推荐
- java异常中throw和throws的区别
throws和throwthrows:用来声明一个方法可能产生的所有异常,不做任何处理而是将异常往上传,谁调用我我就抛给谁. 用在方法声明后面,跟的是异常类名 可以跟多个异常类名,用逗号隔开 表 ...
- log4j配置输出到多个日志文件
通常我们项目里,有一些重要的日志想单独的输出到指定的文件,而不是全总输出到系统的日志文件中.那么我们log4j为我们提供了这种功能,以下我们来一步一步看是怎么做的.这里以property的配置方式写. ...
- iOS开发-工厂模式
工厂模式算是开发中比较常见的设计模式,简单工厂模式,工厂模式和抽象工厂模式,都属于工厂模式.简单工厂模式(simple factory)是类的创建模式,静态工厂方法(static factory me ...
- 一起来给iOS 11找bug: 苹果还是乔布斯时代的细节控吗?
众所周知,前几天苹果在位于苹果公园的Steve Jobs剧院召开了一年一度的新品发布会,正式揭幕了全屏的iPhoneX, 随后又把iOS 11推送给了测试员(Beta Tester)(正式版将于几周后 ...
- 内存优化总结:ptmalloc、tcmalloc和jemalloc(转)
转载于:http://www.cnhalo.net/2016/06/13/memory-optimize/ 概述 需求 系统的物理内存是有限的,而对内存的需求是变化的, 程序的动态性越强,内存管理就越 ...
- SQL Server死锁产生原因及解决办法 .
其实所有的死锁最深层的原因就是一个:资源竞争 表现一: 一个用户A 访问表A(锁住了表A),然后又访问表B,另一个用户B 访问表B(锁住了表B),然后企图访问表A,这时用户A由于用户B已经锁住表B,它 ...
- CorelCAD for Mac(绘图设计软件)破解版安装
1.软件简介 CorelCAD 是 macOS 系统上的 CAD 绘图工具,为我们提供了获取本地 DWG 格式的高性能 CAD 设计解决方案.打开.处理和保存 .DWG 文件,实现轻松协作.借助 ...
- DataTables 全局设置中文语言
参考来源:https://blog.csdn.net/qq_22690445/article/details/79682311 $.fn.dataTable.defaults.oLanguage = ...
- [Android源码]Android源码之高仿飞鸽传书WIFI热点搜索与创建(一)
(本文详情来源:android源码 http://www.eoeandroid.com/thread-296427-1-1.html 转载请注明出处!) [Android源码分享]飞鸽传书的An ...
- 一篇文章掌握RequireJS常用知识
本文采取循序渐进的方式,从理论到实践,从RequireJS官方API文档中,总结出在使用RequireJS过程中最常用的一些用法,并对文档中不够清晰具体的内容,加以例证和分析,分享给大家供大家参考,具 ...