您的位置:首页 > 其它

[二分 前缀优化建图 2-SAT] Codeforces 587D. Duff in Mafia

2017-10-21 14:24 489 查看
二分答案

对于一个点,最多能删一条相连的边,每一种颜色最多能有一条相连的边,那么把每个点相连的边用前缀优化建图就可以了

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>

using namespace std;

const int N=1000010;

int n,m,cnt,tot,G
;
struct iedge{
int s,t,w,c,g;
}ie
;
int tmp
,icnt;
vector<iedge> e
;
struct edge{
int t,nx;
}E[N<<1];

inline void addedge(int x,int y,int c,int t,int g){
e[x].push_back({x,y,t,c,g}); e[y].push_back({x,y,t,c,g});
}

vector<int> cc
;
int tt
,iit;

inline void addedge(int x,int y){
//cout<<x<<' '<<y<<endl;
E[++cnt].t=y; E[cnt].nx=G[x]; G[x]=cnt;
}

int vis
,g
,dfn
,low
,s
,tp,iiit,ig;

void tarjan(int x){
dfn[x]=low[x]=++iiit; vis[x]=1; s[++tp]=x;
for(int i=G[x];i;i=E[i].nx){
if(!vis[E[i].t]) tarjan(E[i].t);
if(vis[E[i].t]!=2) low[x]=min(low[x],low[E[i].t]);
}
if(dfn[x]==low[x]){
int k; ++ig;
do{ k=s[tp--]; vis[k]=2; g[k]=ig; }while(tp && k!=x);
}
}

int lst
;

inline bool check(int x){
memset(G,0,sizeof(G)); cnt=0;
memset(vis,0,sizeof(vis));
for(int i=1;i<=m;i++)
if(ie[i].w>x) addedge(i<<1|1,i<<1);
tot=(m<<1|1)+1;
for(int i=1;i<=n;i++){
++iit;
vector<int> a,b;
for(auto u : e[i]){
if(tt[u.c]!=iit) tt[u.c]=iit,cc[u.c].clear(),a.push_back(u.c);
cc[u.c].push_back(u.g); b.push_back(u.g);
}
if(!b.size()) continue;
addedge(b[0]<<1|1,tot); addedge(tot+1,b[0]<<1);
for(int j=1;j<b.size();j++){
addedge(tot+(j-1<<1),tot+(j<<1));
addedge(tot+(j<<1|1),tot+(j-1<<1|1));
addedge(b[j]<<1|1,tot+(j<<1));
addedge(tot+(j<<1|1),b[j]<<1);
addedge(b[j]<<1|1,tot+(j-1<<1|1));
addedge(tot+(j-1<<1),b[j]<<1);
}
tot+=(b.size()<<1|1)+1;
for(int u : a){
if(cc[u].size()<2) continue;
addedge(cc[u][0]<<1,tot);
addedge(tot+1,cc[u][0]<<1|1);
for(int j=1;j<cc[u].size();j++){
addedge(tot+(j-1<<1),tot+(j<<1));
addedge(tot+(j<<1|1),tot+(j-1<<1|1));
addedge(cc[u][j]<<1,tot+(j<<1));
addedge(tot+(j<<1|1),cc[u][j]<<1|1);
addedge(cc[u][j]<<1,tot+(j-1<<1|1));
addedge(tot+(j-1<<1),cc[u][j]<<1|1);
}
tot+=(cc[u].size()<<1|1)+1;
}
}
tp=iiit=ig=0;
for(int i=2;i<=tot;i++)
if(!vis[i]) tarjan(i);
for(int i=1;i<=m;i++)
if(g[i<<1]==g[i<<1|1]) return false;
memcpy(lst,g,sizeof(g));
return true;
}

int main(){
scanf("%d%d",&n,&m);
for(int i=1,x,y,c,t;i<=m;i++)
scanf("%d%d%d%d",&x,&y,&c,&t),ie[i]={x,y,t,c,i},tmp[++icnt]=c;
sort(tmp+1,tmp+1+icnt); icnt=unique(tmp+1,tmp+1+icnt)-tmp-1;
for(int i=1;i<=m;i++) ie[i].c=lower_bound(tmp+1,tmp+1+icnt,ie[i].c)-tmp;
for(int i=1;i<=m;i++) addedge(ie[i].s,ie[i].t,ie[i].c,ie[i].t,i);
int l=0,r=1e9,mid,ans=-1;
//int ss=check(3);
while(l<=r)
check(mid=l+r>>1)?r=(ans=mid)-1:l=mid+1;
vector<int> pt;
if(!~ans) return puts("No"),0;
puts("Yes");
for(int i=1;i<=m;i++)
if(lst[i<<1|1]<lst[i<<1]) pt.push_back(i);
printf("%d %d\n",ans,pt.size());
for(int u : pt) printf("%d ",u);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: