NOI 2015/ BZOJ 4195 程序自动分析

我们把同值的用一个集合表示。
那么我们把同值的先用并查集连起来,最后再判一下不同值的是否不同集合即可。

小优化:用hash表实现离散化,用时间戳避免memset。
代码:

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define g getchar()
using namespace std;
typedef long long ll;
const int N=(1<<21)-1;
template<class o>void qr(o&x) {
	char c=g;x=0;int f=1;
	while(!isdigit(c)){if(c=='-')f=-1;c=g;}
	while(isdigit(c))x=x*10+c-'0',c=g;
	x*=f;
}
void write(int x) {
	if(x/10)write(x/10);
	putchar(x%10+'0');
}

int fa[N],sz[N];
int findfa(int x) {return fa[x]==x?x:fa[x]=findfa(fa[x]);}
void merge(int x,int y) {
	if(sz[x]>sz[y])fa[y]=x,sz[x]+=sz[y];
	else 		   fa[x]=y,sz[y]+=sz[x];
}

int num[N],nxt[N],len,vis[N],ts;
int find(int x) {
	int k=x&N;
	if(vis[k]==ts) {
		for(	;	;k=nxt[k]) {
			if(num[k]==x)return k;
			if(nxt[k]==-1)break;
		}
		while(vis[len]==ts)len++;
		nxt[k]=len; k=len++;
	}
	num[k]=x;nxt[k]=-1;vis[k]=ts;
	fa[k]=k;sz[k]=1;
	return k;
}

struct no {
	int x,y;
}a[N>>1];int tot;

int main() {
	int T,n;qr(T);
	while(T--) {
		qr(n);bool bk=0;
		len=0;tot=0;ts++;len=0;
		while(n--) {
			int x,y,d;qr(x);qr(y);qr(d);
			if(bk)continue;
			x=findfa(find(x));y=findfa(find(y));
			if(d)merge(x,y);
			else if(x==y)bk=1;
			else a[++tot]=(no){x,y};
		}
		if(!bk)while(tot) {
			int x=a[tot].x,y=a[tot].y;tot--;
			if(findfa(x)==findfa(y)) {bk=1; break;}
		}
		bk?puts("NO"):puts("YES");
	}
	return 0;
}
		
原文地址:https://www.cnblogs.com/zsyzlzy/p/12373884.html