大概题意是删去一组边 这组边是一个匹配
剩下的边 同一颜色的一组边也形成一个匹配
使删去的边最大值最小
这个考虑二分答案 然后检验
- 大于答案的边必然保留
- 同一个点连的同一颜色的边最多保留一条
- 同一个点连的边最多删除一条
这个某些边集最多删一条怎么处理
把他排成一排 那么一个点选了 他的前面都不能选 后面都不能选 那么建前后缀使得边数降到
O(n)
要是裸建图的话是
O(n2)
红点是表示前缀后缀辅助点
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int N=500005;
struct edge{
int u,v,next;
}G[N*10];
int head[N],inum;
int _head[N],tmp;
inline void add(int u,int v){
int p=++inum; G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}
int pre[N],low[N],clk;
int scc[N],cnt; int Stack[N],pnt;
#define V G[p].v
inline void dfs(int u){
pre[u]=low[u]=++clk; Stack[++pnt]=u;
for (int p=head[u];p;p=G[p].next)
if (!pre[V])
dfs(V),low[u]=min(low[u],low[V]);
else if (!scc[V])
low[u]=min(low[u],pre[V]);
if (low[u]==pre[u]){
++cnt;
while (Stack[pnt]!=u) scc[Stack[pnt--]]=cnt; scc[Stack[pnt--]]=cnt;
}
}
int n,m,Tot;
int y[N],vc;
int size[N],sum[N];
inline int pf(int idx,int x){ return (m<<1)+(sum[idx-1]<<1)+x; }
inline int sf(int idx,int x){ return (m<<1)+(sum[idx-1]<<1)+size[idx]+x; }
inline bool Tarjan(){
for (int i=0;i<Tot;i++) pre[i]=low[i]=scc[i]=0; pnt=cnt=clk=0;
for (int i=0;i<Tot;i++)
if (!pre[i])
dfs(i);
for (int i=0;i<2*m;i+=2)
if (scc[i]==scc[i^1])
return 0;
return 1;
}
int us[N],vs[N],ts[N],cs[N];
inline bool check(int x){
if (x==3)
x=3;
for (int i=0;i<m;i++)
if (ts[i]>x)
add(i<<1,i<<1|1);
return Tarjan();
}
int sx[N],icnt;
struct abcd{
int v,c,idx;
abcd(int v=0,int c=0,int idx=0):v(v),c(c),idx(idx) { }
bool operator < (const abcd &B) const{
return v==B.v?c<B.c:v<B.v;
}
}edges[N]; int ecnt;
int ans[N],kans;
int main(){
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(n); read(m);
for (int i=0;i<m;i++) read(us[i]),read(vs[i]),read(cs[i]),read(ts[i]),sx[++icnt]=cs[i];
sort(sx+1,sx+icnt+1); icnt=unique(sx+1,sx+icnt+1)-sx-1;
for (int i=0;i<m;i++){
cs[i]=lower_bound(sx+1,sx+icnt+1,cs[i])-sx;
edges[++ecnt]=abcd(us[i],cs[i],i);
edges[++ecnt]=abcd(vs[i],cs[i],i);
}
sort(edges+1,edges+ecnt+1);
int pnt=1;
while (pnt<=ecnt){
++vc; y[size[vc]++]=edges[pnt++].idx;
while (pnt<=ecnt && edges[pnt].v==edges[pnt-1].v && edges[pnt].c==edges[pnt-1].c)
y[size[vc]++]=edges[pnt++].idx;
for (int j=0;j<size[vc];j++){
if (j-1>=0) add(pf(vc,j),pf(vc,j-1));
add(pf(vc,j),y[j]<<1);
if (j+1<size[vc]) add(sf(vc,j),sf(vc,j+1));
add(sf(vc,j),y[j]<<1);
}
for (int j=0;j<size[vc];j++){
if (j-1>=0) add(y[j]<<1|1,pf(vc,j-1));
if (j+1<size[vc]) add(y[j]<<1|1,sf(vc,j+1));
}
sum[vc]=sum[vc-1]+size[vc];
}
pnt=1;
while (pnt<=ecnt){
++vc; y[size[vc]++]=edges[pnt++].idx;
while (pnt<=ecnt && edges[pnt].v==edges[pnt-1].v)
y[size[vc]++]=edges[pnt++].idx;
for (int j=0;j<size[vc];j++){
if (j-1>=0) add(pf(vc,j),pf(vc,j-1));
add(pf(vc,j),y[j]<<1|1);
if (j+1<size[vc]) add(sf(vc,j),sf(vc,j+1));
add(sf(vc,j),y[j]<<1|1);
}
for (int j=0;j<size[vc];j++){
if (j-1>=0) add(y[j]<<1,pf(vc,j-1));
if (j+1<size[vc]) add(y[j]<<1,sf(vc,j+1));
}
sum[vc]=sum[vc-1]+size[vc];
}
Tot=(m<<1)+(sum[vc]<<1);
for (int i=0;i<2*m;i++) _head[i]=head[i]; tmp=inum;
if (!Tarjan()) { printf("No\n"); return 0; }
int L=-1,R=1<<30,MID;
while (L+1<R){
if (check(MID=(L+R)>>1))
R=MID;
else
L=MID;
for (int i=0;i<2*m;i++) head[i]=_head[i]; inum=tmp;
}
check(R);
printf("Yes\n");
for (int i=0;i<m;i++){
ans[i]=scc[i<<1|1]<scc[i<<1];
if (!ans[i]) kans++;
}
printf("%d %d\n",R,kans);
for (int i=0;i<m;i++) if (!ans[i]) printf("%d ",i+1);
return 0;
}