题解 P1955 [NOI2015]程序自动分析

P1955 [NOI2015]程序自动分析

题目链接

 

分析废话

首先看到这道题,我们应该先思考怎样才能判断一个约束条件会导致整个问题矛盾。

题目中的约束条件有两种,相等和不相等

很显然,相等条件是不会互相冲突的(大家都相等)
不等条件也不会互相冲突(大家都不相等)
所以产生冲突的原因是不等关系和相等关系之间不能同时成立

废话题干里都说了

那么在顺序读入的过程中如何查看当前条件是否和已知条件矛盾呢?
由于等式的传递性所以我们可以把所有相等的元素抽象成一个集合,集合中每一个元素都相等

集合内每一个元素要满足快速的合并到其它集合查找该集合的代表元素

我们就灵光一闪自然而然地想到了并 查集

所以我们的思路就是把所有相等的点并在一个集合里。判断不等时,如果约束条件里的两个元素已经属于同一个集合(根据已知条件这两个元素相等),那么该约束条件与其他条件矛盾,跳出即可。

 

注意

 

1.数据范围

注意i,j的数据规模是1e9,因为并查集的fa数组无法开到那么大即便内存给512M所以必须使用离散化把这些大得离谱的i,j缩到1-2m之间(m是变量的个数)

离散化概述-百度百科 <--参考资料

 

2.小细节

处理条件的顺序

由上文分析所述,可见先合并完所有相等的条件再判断不等的条件,所以在读入条件后应该对条件排序,代码中用了结构体排序 ,使得标记为1的条件排在标记为0的前面

数组的初始化

处理离散化需要用到的inp(记录输入的变量名称)和b(去重后的离散化数组)

并查集所用的fa数组

在每次询问前 统统都要初始化

不然各种REMLEWA...

好吧废话说到这里看代码吧 自认为注释说得很清楚(逃

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <functional>
using namespace std;
#define N 1000000
#define ll long long
#define re register
int T, n, cnt;
//循环次数 约束条件数量 变量数量(未去重)
int inp[N << 1], b[N], m, fa[N << 1];
//输入 去重数组 变量数量(已去重) 父亲数组(并查集)
inline int read()
{
	int x = 0, f = 1;
	char c = getchar();
	while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
	while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
	return x * f;
}//快读

struct node //约束条件结构体
{
	int x, y, tp;
}a[N];//数字x和数字y的关系 tp表示类型

void discrete()
{
	sort(inp + 1, inp + 1 + cnt);
	for (int i = 1; i <= cnt; i++)
		if (i == 1 || inp[i] != inp[i - 1])
			b[++m] = inp[i];
}//去重

int query(int x) { return lower_bound(b + 1, b + 1 + m, x) - b; }//离散化
bool cmp(node a1, node a2) { return a1.tp > a2.tp; }//对约束条件进行排序

int getfather(int x) { return fa[x] = x == fa[x] ? x : getfather(fa[x]); }//并查集
bool check(int x, int y) { return getfather(x) == getfather(y); }
//查
void merge(int x, int y)
{
	int xx = getfather(x), yy = getfather(y);
	if (xx != yy) fa[xx] = yy;
}//并

int main()
{
	T = read();
	for (int tp = 0; tp < T; tp++)
	{
		memset(fa, 0, sizeof(fa));//一定不能忘记初始化 (其实可以记忆用了多少万一T大起来)
		memset(inp, 0, sizeof(inp));
		memset(b, 0, sizeof(b));
		bool flag = true;//是否成立(有矛盾)
		n = read();
		for (int i = 1; i <= n; i++) //读入关系
			a[i].x = read(), a[i].y = read(), a[i].tp = read(), inp[++cnt] = a[i].x, inp[++cnt] = a[i].y;
		discrete();//离散化
		for (int i = 1; i <= n; i++)
			a[i].x = query(a[i].x), a[i].y = query(a[i].y);//离散化
		for (int i = 1; i <= m; i++)
			fa[i] = i;//并查集初始化
		sort(a + 1, a + 1 + n, cmp);//将约束条件排序
		for (int i = 1; i <= n; i++)
		{
			if (a[i].tp == 1) merge(a[i].x, a[i].y);//若相等则并
			else if (check(a[i].x, a[i].y))//若不等则查
			{
				flag = false;
				break;
			}
		}
		if (flag) printf("YES\n");
		else printf("NO\n");//输出结果
	}
}

19.08.01

posted @ 2019-10-05 16:02  Yuanqi_Yu  阅读(220)  评论(0)    收藏  举报