CSU OJ:1241 数字序列(并查集+思维)

1241: 数字序列

            Time Limit: 1 Sec       Memory Limit: 128 Mb       Submitted: 200       Solved: 31    

Description

Staginner在纸上依次写下了n个数,分别记为a1,a2,...,an,然后他给CSGrandeur提供了p条信息,现在CSGrandeur想知道,依据Staginner提供的信息,这个数列能否被唯一确定呢?

Input

输入包含若干组数据,每组数据的第一行有2个正整数,n(1<=n<=10000),p(0<=p<=20000),其中n、p的含义同上。
接下来一共有p行,每行的开头有一个字符B或S。如果为B,则B后面有3个整数i(1<=i<=n),j(1<=j<=n),k(-5000<=k<=5000),表示ai比aj大k,也即ai=aj+k;如果为S,则S后面有2个整数i(1<=i<=n),j(-5000<=j<=5000),表示ai的值为j。

Output

对于每组数据,如果根据给出的p条信息可以唯一确定出这个数列,则输出“AC”,如果p条信息可以推出矛盾,则输出“RE”,如果不能唯一确定出这个数列且p条信息并不矛盾,则输出“WA”。

Sample Input

3 3
B 2 1 1
B 3 2 1
S 2 0
2 3
B 2 1 1
S 1 0
S 2 0 
3 2
B 2 1 1
B 3 2 1

Sample Output

AC
RE
WA

Hint

Source

CSU Monthly 2012 Feb.

用相对来统计,有点瞌睡头蒙,代码如下:

#include <cstdio>
#include <cstring> 
int vis[10010],num[10010],r[10010],fa[10010];//vis表示该头目节点是否访问过   num[i]表示i作为头目节点所表示的数,但不是确切的数,相对于集体来讲的    r[i]表示i节点与头目节点的相对值  fa[i]是i的父节点 
int find(int x) //压缩路径,并且使得r[i]等于i相对于根节点的值的大小 
{
	if(x==fa[x])
	{
		return x;
	}
	int tmp=fa[x];
	fa[x]=find(fa[x]);
	r[x]=r[x]+r[tmp];
	return fa[x];
}
int main()
{
	int n,m;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		char op[2];
		memset(vis,0,sizeof(vis));
		memset(num,0,sizeof(num));
		for(int i=1;i<=n;i++)
		{
			fa[i]=i;
			r[i]=0;
		}
		int flag=0;
		for(int i=0;i<m;i++)
		{
			scanf("%s",op);
			if(op[0]=='B')
			{
				int a,b,c;
				scanf("%d%d%d",&a,&b,&c);
				int fx=find(a);
				int fy=find(b);
				if(fx!=fy)//两集体合并 
				{
					fa[fy]=fx;
					r[fy]=r[a]-r[b]-c;//更新b的头目节点相对于a的头目节点的大小 
					if(vis[fy])//如果b的集体已经有确切的值了 
					{
						int tmp=num[fy]-r[fy];
						if(vis[fx])//如果a集体也已经有确切的值了 
						{
							if(num[fx]!=tmp)//
							{
								flag=1;
							}
						}
						else
						{
							num[fx]=tmp;
							vis[fx]=1;
						}
					}
				}
				else//ab是一个集体中的 
				{
					if(r[a]-r[b]!=c)
					{
						flag=1;
					}
				}
			}
			else
			{
				int a,b;
				scanf("%d%d",&a,&b);
				int fx=find(a);
				int tmp=b-r[a];
				if(vis[fx])
				{
					if(num[fx]!=tmp)
					{
						flag=1;
					}
				}
				else
				{
					num[fx]=tmp;
					vis[fx]=1;
				}
			}
		}
		if(flag)
		{
			printf("RE\n");
		}
		else
		{
			for(int i=1;i<=n;i++)
			{
				if(find(i)==i&&vis[i]==0)
				{
					flag=1;
					break;
				}
			}
			if(flag)
			{
				printf("WA\n");
			}
			else
			{
				printf("AC\n");
			}
		}
	}
	return 0;
 } 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值