给一个愚蠢做法。
考虑每种颜色的边构成的子图。显然有某个点度数
>
2
>2
>2无解,于是每个连通块只能是环或链。对于环,如果是奇环显然无解,偶环的话里面每个点都必须用到(已经被用到也无解),直接取两种情况较小的即可。对于链,非两个端点的点都必须用到(否则也无解),如果链的边数为奇数,可以额外用到两个端点,可能得到更小的答案,如果为偶数,必须恰好多用一个端点,得到两个方案。
考虑二分答案后判定。对于边数为奇数的链容易做出选择(尽可能不用额外点),对于边数为偶数的,如果只有至多一个端点能选同样类似,两个都能选的话我们可以在两个端点间连一条边,这样每个连通块必须是树或环套树。输出方案类似搞搞就行了。
时间复杂度
O
(
n
log
n
)
\mathcal O(n\log n)
O(nlogn)。这个做法代码要6k+,难写又难调,正常做法是简单的二分后前后缀优化2-sat。。。不过这个跑的非常快,比2-sat快几倍。
#include <bits/stdc++.h>
#define FR first
#define SE second
using namespace std;
typedef pair<int,int> pr;
struct Data {
int x,y,v1,v2;
Data() {}
Data(int a,int b,int c,int d):x(a),y(b),v1(c),v2(d) {}
};
Data a[50005],b[50005];
vector <int> bel1[50005],bel2[50005];
int sz1,sz2;
struct Edge {
int s,t,v;
Edge() {}
Edge(int a,int b,int c):s(a),t(b),v(c) {}
};
Edge e1[50005];
bool vis[50005],use[50005];
vector <int> ans;
map <int,int> mp;
vector <int> ee[50005];
vector <pr> e2[50005];
int d[50005],node[100005];
int build(int x) {
int cnt=0;
for(int i=0;i<ee[x].size();i++) {
int u=e1[ee[x][i]].s,v=e1[ee[x][i]].t;
node[++cnt]=u;node[++cnt]=v;
d[u]++;d[v]++;
e2[u].push_back(pr(v,ee[x][i]));
e2[v].push_back(pr(u,ee[x][i]));
}
sort(node+1,node+cnt+1);
cnt=unique(node+1,node+cnt+1)-node-1;
for(int i=1;i<=cnt;i++)
if (d[node[i]]>2) {
puts("No");
exit(0);
}
for(int i=1;i<=cnt;i++)
if (d[node[i]]==1) {
int u=node[i];
vector<int> cur1,cur2;
for(;;) {
cur2.push_back(u);
bool ok=0;
for(int j=0;j<e2[u].size();j++)
if (!vis[e2[u][j].SE]) {
int v=e2[u][j].FR,t=e2[u][j].SE;
cur1.push_back(t);
vis[t]=1;
d[u]--;d[v]--;
u=v;ok=1;
break;
}
if (!ok) break;
}
for(int j=1;j<cur2.size()-1;j++) {
int u=cur2[j];
if (use[u]) {
puts("No");
exit(0);
}
use[u]=1;
}
int max1=0,max2=0;
for(int j=0;j<cur1.size();j++)
if (!(j&1)) max1=max(max1,e1[cur1[j]].v); else max2=max(max2,e1[cur1[j]].v);
if ((cur1.size())&1) {
a[++sz1]=Data(cur2[0],cur2[cur2.size()-1],max1,max2);
bel1[sz1]=cur1;
}
else {
b[++sz2]=Data(cur2[0],cur2[cur2.size()-1],max1,max2);
bel2[sz2]=cur1;
}
}
int maxn=0;
for(int i=1;i<=cnt;i++)
if (d[node[i]]==2) {
int u=node[i];
vector<int> cur1,cur2;
for(;;) {
cur2.push_back(u);
bool ok=0;
for(int j=0;j<e2[u].size();j++)
if (!vis[e2[u][j].SE]) {
int v=e2[u][j].FR,t=e2[u][j].SE;
cur1.push_back(t);
vis[t]=1;
d[u]--;d[v]--;
u=v;ok=1;
break;
}
if (!ok) break;
}
cur2.pop_back();
for(int j=0;j<cur2.size();j++) {
int u=cur2[j];
if (use[u]) {
puts("No");
exit(0);
}
use[u]=1;
}
if (cur1.size()&1) {
puts("No");
exit(0);
}
int max1=0,max2=0;
for(int j=0;j<cur1.size();j++)
if (!(j&1)) max1=max(max1,e1[cur1[j]].v); else max2=max(max2,e1[cur1[j]].v);
if (max1<max2) {
maxn=max(maxn,max1);
for(int j=0;j<cur1.size();j+=2) ans.push_back(cur1[j]);
}
else {
maxn=max(maxn,max2);
for(int j=1;j<cur1.size();j+=2) ans.push_back(cur1[j]);
}
}
for(int i=1;i<=cnt;i++) e2[node[i]].clear();
return maxn;
}
bool use2[50005];
vector <pr> e3[50005];
int vis2[50005],vis_cnt;
int s1,s2,rt,ban;
int p[50005],vis3[50005];
void dfs1(int x,int fa) {
vis2[x]=vis_cnt;
s1++;s2+=(int)e3[x].size();
for(int i=0;i<e3[x].size();i++)
if (e3[x][i].SE!=fa) {
int u=e3[x][i].FR;
if (u==x) s2++;
if (vis2[u]<vis_cnt) dfs1(u,e3[x][i].SE);
else {
ban=e3[x][i].SE;
p[ban]=x;
rt=x;
}
}
}
void dfs2(int x) {
vis3[x]=vis_cnt;
for(int i=0;i<e3[x].size();i++)
if (e3[x][i].SE!=ban&&vis3[e3[x][i].FR]<vis_cnt) {
int u=e3[x][i].FR;
p[e3[x][i].SE]=u;
dfs2(u);
}
}
bool check(int n,int d) {
vis_cnt++;
for(int i=1;i<=n;i++) {
use2[i]=use[i];
e3[i].clear();
}
for(int i=1;i<=sz1;i++)
if (a[i].v2>d) {
if (a[i].v1>d||use2[a[i].x]||use2[a[i].y]) return 0;
use2[a[i].x]=use2[a[i].y]=1;
}
for(int i=1;i<=sz2;i++)
if (b[i].v1<=d&&b[i].v2<=d&&!use2[b[i].x]&&!use2[b[i].y]) {
int u=b[i].x,v=b[i].y;
e3[u].push_back(pr(v,i));
e3[v].push_back(pr(u,i));
}
else if (b[i].v1<=d&&!use2[b[i].x]) {
int u=b[i].x;
e3[u].push_back(pr(u,i));
}
else if (b[i].v2<=d&&!use2[b[i].y]) {
int u=b[i].y;
e3[u].push_back(pr(u,i));
}
else return 0;
for(int i=1;i<=n;i++)
if (vis2[i]<vis_cnt) {
s1=s2=0;
dfs1(i,0);
if (s1<(s2>>1)) return 0;
}
return 1;
}
void output(int n,int d) {
vis_cnt++;
vector<int> cur;
for(int i=1;i<=n;i++) {
use2[i]=use[i];
e3[i].clear();
}
for(int i=1;i<=sz1;i++)
if (a[i].v2<=d) {
for(int j=1;j<bel1[i].size();j+=2) ans.push_back(bel1[i][j]);
}
else {
use2[a[i].x]=use2[a[i].y]=1;
for(int j=0;j<bel1[i].size();j+=2) ans.push_back(bel1[i][j]);
}
for(int i=1;i<=sz2;i++)
if (b[i].v1<=d&&b[i].v2<=d&&!use2[b[i].x]&&!use2[b[i].y]) {
int u=b[i].x,v=b[i].y;
e3[u].push_back(pr(v,i));
e3[v].push_back(pr(u,i));
}
else if (b[i].v1<=d&&!use2[b[i].x]) {
int u=b[i].x;
e3[u].push_back(pr(u,i));
}
else if (b[i].v2<=d&&!use2[b[i].y]) {
int u=b[i].y;
e3[u].push_back(pr(u,i));
}
for(int i=1;i<=n;i++)
if (vis2[i]<vis_cnt) {
s1=s2=rt=ban=0;
dfs1(i,0);
if (!rt) dfs2(i); else dfs2(rt);
}
for(int i=1;i<=sz2;i++)
if (p[i]==b[i].x) {
for(int j=0;j<bel2[i].size();j+=2) ans.push_back(bel2[i][j]);
}
else {
for(int j=1;j<bel2[i].size();j+=2) ans.push_back(bel2[i][j]);
}
sort(ans.begin(),ans.end());
}
int main() {
int n,m;
scanf("%d%d",&n,&m);
int cnt=0,l=0,r=0;
for(int i=1;i<=m;i++) {
int a,b,c,d;
scanf("%d%d%d%d",&a,&b,&c,&d);
if (!mp.count(c)) mp[c]=++cnt;
c=mp[c];
e1[i]=Edge(a,b,d);
ee[c].push_back(i);
r=max(r,d);
}
for(int i=1;i<=cnt;i++)
l=max(l,build(i));
if (!check(n,r)) {
puts("No");
return 0;
}
while (l<r) {
int mid=((l+r)>>1);
if (check(n,mid)) r=mid; else l=mid+1;
}
output(n,l);
puts("Yes");
printf("%d %d\n",l,(int)ans.size());
for(int i=0;i<ans.size();i++) printf("%d ",ans[i]);
printf("\n");
return 0;
}