cf949C

题意简述:有n个点,每一个点都有一个权值,然后有m个条件,每一个条件是a[x]!=a[y],让选择最少的点且至少选择1个,然后让这个点的权值+1,使得条件仍满足

所有数对k取模

题解:如果a[x]+1=a[y]那么x向y连边,a[y]+1=a[x]那么y向x连边,此时答案等于缩点之后出度为0的分量中点最少的一个

#include<bits/stdc++.h>
#define forn(i, n) for (int i = 0 ; i < int(n) ; i++)
#define fore(i, s, t) for (int i = s ; i < (int)t ; i++)
#define fi first
#define se second
#define all(x) x.begin(),x.end()
#define pf2(x,y) printf("%d %d\n",x,y)
#define pf(x) printf("%d\n",x)
#define each(x) for(auto it:x)  cout<<it<<endl;
#define pi pair<int,int>
using namespace std;
typedef long long ll;
const int maxn=1e6+5;
const int maxm=2e5+5;
const int inf=1e9;
int head[maxn],ver[maxm],nex[maxm],tot;
void inline AddEdge(int x,int y){
	ver[++tot]=y,nex[tot]=head[x],head[x]=tot;
}
int dfn[maxn],low[maxn],num,sccnum,scc[maxn],s[maxn],d[maxn],cnt[maxn],top;
void Tarjan(int x){
	low[x]=dfn[x]=++num;
	s[++top]=x;
	for(int i=head[x];i;i=nex[i]){
		int y=ver[i];
		if(!dfn[y]) {
			Tarjan(y);
			low[x]=min(low[x],low[y]);
		}
		else if(!scc[y]) low[x]=min(low[x],dfn[y]);
	}
	if(low[x]==dfn[x]){
		sccnum++;
		while(s[top]!=x){
			scc[s[top]]=sccnum;
			top--;
			cnt[sccnum]++;
		}
		cnt[sccnum]++;
		scc[s[top]]=sccnum;
		top--;
	}
}
int n,m,k,a[maxn];
int main(){
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for(int i=0;i<m;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		if((a[x]+1)%k==a[y]) AddEdge(x,y);
		if((a[y]+1)%k==a[x]) AddEdge(y,x);
	} 
	for(int i=1;i<=n;i++)
		if(!dfn[i]) Tarjan(i);
	for(int x=1;x<=n;x++)
		for(int i=head[x];i;i=nex[i]){
			int y=ver[i];
			if(scc[x]!=scc[y]) {
				d[scc[x]]++;
			}
		}
	int idx=0;
	cnt[idx]=1e9;
	for(int i=1;i<=n;i++){
		if(d[scc[i]]==0 && cnt[scc[i]]<cnt[scc[idx]])
			idx=i;
	}
	cout<<cnt[scc[idx]]<<endl;
	for(int i=1;i<=n;i++)
		if(scc[idx]==scc[i]) cout<<i<<' ';
	cout<<endl;
	return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/033000-/p/12345990.html