Codeforces 587D

100 篇文章 0 订阅
16 篇文章 0 订阅

给一个愚蠢做法。
考虑每种颜色的边构成的子图。显然有某个点度数 > 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值