数据分割
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2091 Accepted Submission(s): 607
Problem Description
小w来到百度之星的赛场上,准备开始实现一个程序自动分析系统。
这个程序接受一些形如xi=xj 或 xi≠xj 的相等/不等约束条件作为输入,判定是否可以通过给每个 w 赋适当的值,来满足这些条件。
输入包含多组数据。
然而粗心的小w不幸地把每组数据之间的分隔符删掉了。
他只知道每组数据都是不可满足的,且若把每组数据的最后一个约束条件去掉,则该组数据是可满足的。
请帮助他恢复这些分隔符。
Input
第1 行:一个数字L ,表示后面输入的总行数。
之后L 行,每行包含三个整数,i,j,e ,描述一个相等/不等的约束条件,若e=1 ,则该约束条件为xi=xj ,若e=0 ,则该约束条件为 xi≠xj 。
i,j,L≤100000
xi,xj≤L
Output
输出共T+1 行。
第一行一个整数T ,表示数据组数。
接下来T 行的第i 行,一个整数,表示第i组数据中的约束条件个数。
Sample Input
6 2 2 1 2 2 1 1 1 1 3 1 1 1 3 1 1 3 0
Sample Output
1 6
题意就是有n个数,不断给你条件,如i=j或i!=j
你要把条件扔进一个栈里。
若出现一个条件和栈里的条件出现冲突
输出栈的大小+1&&清空栈
等于是满足传递性的,故等于关系可以用并查集维护,同一个集合的表示它们都相等。
若出现不等关系,且它们在同一个集合里,则冲突,否则这两个点连一条边
如果来了一个相等关系,且它们所在的两个集合之间有连边,则冲突,否则合并这两个集合。
具体实现就是启发式合并,两个点连边等价于在两个点所在集合的根结点连边。
合并两个集合时就把和“边数较小的集合的根”有关的边,一条一条接到另一个集合的根上。
对于每一条边,每合并一次它所在的集合边数至少*2,故它的合并次数都不会超过log(n)。
#include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
#define mmst(a, b) memset(a, b, sizeof(a))
#define mmcp(a, b) memcpy(a, b, sizeof(b))
typedef long long LL;
const int N=100100,M=2002000;
int m,n,mx;
int fa[N];
int ans[N],top;
int cnt,to[M],head[N],num[N],nex[M];
void init(int x)
{
for(int i=0;i<=x;i++)
{
fa[i]=i;
num[i]=head[i]=0;
}
mx=0;
cnt=1;
}
void add(int u,int v)
{
num[u]++;
to[++cnt]=v;
nex[cnt]=head[u];
head[u]=cnt;
}
int find(int x)
{
if(fa[x]==x)
return x;
fa[x]=find(fa[x]);
return fa[x];
}
bool unite(int a,int b)
{
if(a!=b)
{
if(num[a]>num[b])
swap(a,b);
num[b]+=num[a];
fa[a]=b;
int last=0;
for(int h=head[a];h;h=nex[h])
{
if(to[h]==b)
return false;
to[h^1]=b;
last=h;
}
if(last)
{
nex[last]=head[b];
head[b]=head[a];
}
}
return true;
}
int main()
{
cin>>n;
init(100000);
int now=0,u,v,ops;
for(;;)
{
now++;
bool ok=true;
scanf("%d%d%d",&u,&v,&ops);
mx=max(mx,u);
mx=max(mx,v);
u=find(u);
v=find(v);
if(!ops)
{
if(u==v)
ok=false;
add(u,v);
add(v,u);
}
else
if(!unite(u,v))
ok=false;
if(!ok)
{
ans[++top]=now;
init(mx);
}
if(now==n)
break;
}
cout<<top<<endl;
for(int i=1;i<=top;i++)
printf("%d\n",ans[i]-ans[i-1]);
return 0;
}