2018 CodeM复赛:B. 软件包管理器(二分)

链接:https://www.nowcoder.com/acm/contest/152/B
来源:牛客网

题目描述

    点点现在有n个软件包。他想设计一个软件包管理器。不可避免地,他要解决软件包之间的依赖问题。
    一开始这些软件包之间没有依赖关系。但是每次点点会添加一条依赖关系a,b,表示软件包a依赖b。当这些软件包的依赖关系没有环的时候,那么这个软件包的管理器是好的,否则就是不好的。
    环的定义如下:
    对于任意k(k≥2)个软件包{a 1,a 2,...,a k},若对于所有的i<k满足a i依赖a i+1,且a 1=a k成立,则这k个软件包构成一个环。
    点点想让你回答他每次加入一条依赖关系之后这个软件包是不是好的,如果是好的那么输出1,否则输出0。同时,点点希望他在加入每一条关系之后你都能回答他,所以他会在读入中对数据进行加密。你只有回答了问题才能知道下一条依赖关系是什么。

输入描述:

第一行两个正整数n,m (1≤n≤100,000, 1≤m≤200,000),表示软件包的个数和操作个数。软件包的标号为1到n。
接下来m行,每行两个正整数u’, v’,表示加密后的依赖关系,保证u’≠v’。如果上一个回答为ans,实际的依赖关系为u, v,那么u’=(u+ans) mod n+1, v’=(v+ans) mod n+1。一开始的ans为0。

输出描述:

输出m行,每行一个数0或1,表示加入了一条依赖关系之后的回答。


题意:一张有向图,一条边一条边的加,问什么时候开始出现环

二分即可,强制在线是假的


#include<stdio.h>
#include<algorithm>
#include<vector>
using namespace std;
typedef struct
{
	int x, y;
}Res;
Res s[200005];
vector<int> G[100005];
int n, m, ok, vis[100005];
int P(int x)
{
	x -= 2;
	if(x==0)
		x = n;
	else if(x==-1)
		x = n-1;
	return x;
}
void Sech(int x)
{
	int i, v;
	vis[x] = 1;
	for(i=0;i<G[x].size();i++)
	{
		v = G[x][i];
		if(vis[v]==2)
			continue;
		if(vis[v]==1)
		{
			ok = 1;
			continue;
		}
		Sech(v);
	}
	vis[x] = 2;
}
int Jud(int x)
{
	int i;
	G[s[1].x-1].push_back(s[1].y-1);
	for(i=2;i<=x;i++)
		G[P(s[i].x)].push_back(P(s[i].y));
	for(i=1;i<=n;i++)
		vis[i] = 0;
	ok = 0;
	for(i=1;i<=n;i++)
	{
		if(vis[i]==0)
			Sech(i);
	}
	for(i=1;i<=n;i++)
		G[i].clear();
	return ok;
}
int main(void)
{
	int i, l, r, mid;
	scanf("%d%d", &n, &m);
	for(i=1;i<=m;i++)
		scanf("%d%d", &s[i].x, &s[i].y);
	l = 1, r = m;
	while(l<r)
	{
		mid = (l+r+1)/2;
		if(Jud(mid))
			r = mid-1;
		else
			l = mid;
	}
	for(i=1;i<=r;i++)
		printf("1\n");
	for(;i<=m;i++)
		printf("0\n");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/jaihk662/article/details/80958727