COCI 2018/2019 Round1 Teoretičar

版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/qq_35950004/article/details/84728876

Little Alan was bored so he asked Goran to give him an interesting problem. Since he’s busy with
preparing for exams, Goran could only recall one huge bipartite graph from his old days as a
programming competitor. He gave the graph to Alan and said: ​You have to colour the edges of this
bipartite graph using as few colours as possible in such a way that there are no two edges of the
same colour sharing a node.
Alan excitedly ran to his room, took out his movable read/write device for its tape and start to work on
the problem. However, he soon realized that he’s missing something so he got back to Goran and
said: ​Give me an infinite tape and I will solve your problem! Goran gave him a significant look: ​Infinite
tape? If you continue to theorize about everything, there won’t be a single thing named after you.
After seeing Alan starting to tear up, Goran decided to show mercy: ​I will make it a bit easier for you.
Let C be the smallest number of colours needed to paint the graph in the described way. I will let you
use at most X colours, where X is the lowest power of 2 not less than C.
Help Alan solve the problem.
Note ​: A bipartite graph is a graph whose nodes can be divided in two sets (or sides) in such a way
that each edge of graph connects one node from the first set with one node from the second set.

题意:一个二分图,给边染色使得共点的边不同色,且用的颜色数量小于等于2k,其中k是最小的k满足2k>=最小的满足条件的颜色数,求染色方案。
点数n<=200000,边数m<=500000
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
这个。乍一看可以乱搞,但是。。。。
首先可以想到一次给两种颜色,一直给直到结束,然后,它WA了。
可以猜到最小颜色数为最大点度数,但是直接染是O(n^2)的。
考虑把这些边分为两个部分,使得每个点的度数都尽量被这两个部分平分。
然后递归处理。
边的分割用欧拉回路(适当加虚点和虚边使得每个点的度数都为偶数)
每次看外国网友的代码都觉得他们太依赖STL了(还有就是代码又长又丑又易懂)。
所以经常打CF会得STL依赖症?

AC Code:

#include<bits/stdc++.h>
#define maxn 200005
#define maxm 1000005
using namespace std;

int m,n,l,r;
struct node{ int u,v; };
vector<node>edge,G;
vector<int>g[maxn];
int vis[maxm],tim,col[maxm],in[maxn];
int cl=0;

void dfs(int now)
{
	for(;g[now].size();)
	{
		int v = g[now].back();
		g[now].pop_back();
		if(vis[v]==tim) continue;
		col[v] = (cl^=1);
		vis[v] = tim;
		dfs(G[v].u == now ? G[v].v : G[v].u);
	}
}

vector<int>solve(vector<node>e)
{
	if(!e.size())
	{
		return {};
	}
	++tim;
	G=e;
	int cnt_e = e.size() , siz = cnt_e;
	vector<int>pt;
	for(int i=0;i<cnt_e;i++)
	{
		if(vis[e[i].u]!=tim) vis[e[i].u]=tim,g[e[i].u].clear(),in[e[i].u]=0,pt.push_back(e[i].u);
		if(vis[e[i].v]!=tim) vis[e[i].v]=tim,g[e[i].v].clear(),in[e[i].v]=0,pt.push_back(e[i].v);
		in[e[i].u]++,in[e[i].v]++;
		g[e[i].u].push_back(i);
		g[e[i].v].push_back(i);
	} 
	bool flag=0;
	for(vector<int>::iterator it = pt.begin();it!=pt.end();it++)
		flag |= g[*it].size() > 1;
	if(!flag)
	{
		vector<int>ret;
		for(int i=0;i<siz;i++) ret.push_back(1);
		return ret; 
	}
	in[n+1] = 0;
	for(vector<int>::iterator it = pt.begin();it!=pt.end();it++)
		if(in[(*it)] & 1) 
			if((*it)<=l)
			{
				g[n+2].push_back(cnt_e),
				in[n+2]++;
				g[*it].push_back(cnt_e++),
				G.push_back(node{*it,n+2});
			}
			else
			{
				g[n+1].push_back(cnt_e),in[n+1]++,
				g[*it].push_back(cnt_e++);
				G.push_back(node{n+1,*it});
			}
	if(in[n+1] & 1) 
		g[n+2].push_back(cnt_e),
		g[n+1].push_back(cnt_e++),
		G.push_back(node{n+1,n+2});
	++tim;
	for(vector<int>::iterator it = pt.begin();it!=pt.end();it++)
		dfs(*it);
	vector<node>tx,ty;
	vector<int>ccl;
	for(int i=0;i<siz;i++)
	{
		if(col[i]) ty.push_back(e[i]);
		else tx.push_back(e[i]);
		ccl.push_back(col[i]);
	}
	vector<int>rx=solve(tx),ry=solve(ty);
	int hx = *max_element(rx.begin(),rx.end()) , px=0,py=0;
	vector<int>ret;
	for(int i=0;i<siz;i++)
		if(ccl[i]) ret.push_back(ry[py++] + hx);
		else ret.push_back(rx[px++]);
	return ret;
}

int main()
{
	scanf("%d%d%d",&l,&r,&m),n=l+r;
	for(int i=1,u,v;i<=m;i++)
		scanf("%d%d",&u,&v),
		edge.push_back(node{u,v+l});
	vector<int>ans = solve(edge);
	printf("%d\n",*max_element(ans.begin(),ans.end()));
	for(int i=0;i<m;i++)
		printf("%d\n",ans[i]);
}

猜你喜欢

转载自blog.csdn.net/qq_35950004/article/details/84728876