[二分 前缀优化建图 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; }
相关文章推荐
- Codeforces 479E Riding in a Lift【Dp+前缀和优化+二分】好题~
- [二分答案 2-SAT验证 前缀后缀优化建图 线段树优化建图] Codeforces gym 100159 Facebook Hacker Cup 2012 I. Unfriending
- [线段树 & 前缀 优化建图 二分 2-SAT] CF Gym100159 facebook-hacker-cup-2012 I. Unfriending
- [二分答案 2-SAT验证 前后缀优化建图] Codeforces 587D #326 (Div. 1) D. Duff in Mafia
- 【CF587D】Duff in Mafia 二分+前缀优化建图+2-SAT
- Codeforces 460C Present 二分+前缀和
- 【codeforces】gym 101138 K. The World of Trains【前缀和优化dp】
- noip2011 聪明的质监员 (二分+前缀和处理+读入优化)
- [UOJ210]-寻找罪犯-前缀边优化2-SAT
- 一个有趣的题目【二分答案,2-SAT,线段树优化】
- Codeforces 676C - Vasya and String 详解(二分前缀和+尺取两种写法)
- 【2-SAT+前缀优化建图】BZOJ3495 PA2010 Riddle
- 违禁词过滤完整设计与优化(前缀匹配、二分查找)
- [UOJ]210 寻找罪犯 2-Sat 前缀和优化
- [BZOJ]3495 Riddle 2-Sat 前缀和优化
- [BZOJ1044][HAOI2008]木棍分割 二分+贪心+dp+前缀和优化
- Codeforces 460C Present【二分+思维优化】
- bzoj3495 PA2010 Riddle(2-SAT 前缀优化建边)
- 1044: [HAOI2008]木棍分割 二分答案+DP+前缀和优化
- CodeForces 460C——二分+前缀和—— Present