程序自动分析(BZOJ 4195)

Description

 在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足。

考虑一个约束满足问题的简化版本:假设x1,x2,x3,…代表程序中出现的变量,给定n个形如xi=xj或xi≠xj的变量相等/不等的约束条件,请判定是否可以分别为每一个变量赋予恰当的值,使得上述所有约束条件同时被满足。例如,一个问题中的约束条件为:x1=x2,x2=x3,x3=x4,x1≠x4,这些约束条件显然是不可能同时被满足的,因此这个问题应判定为不可被满足。
现在给出一些约束满足问题,请分别对它们进行判定。

Input

输入文件的第1行包含1个正整数t,表示需要判定的问题个数。注意这些问题之间是相互独立的。

对于每个问题,包含若干行:
第1行包含1个正整数n,表示该问题中需要被满足的约束条件个数。
接下来n行,每行包括3个整数i,j,e,描述1个相等/不等的约束条件,相邻整数之间用单个空格隔开。若e=1,则该约束条件为xi=xj;若e=0,则该约束条件为xi≠xj。

Output

输出文件包括t行。

输出文件的第k行输出一个字符串“YES”或者“NO”(不包含引号,字母全部大写),“YES”表示输入中的第k个问题判定为可以被满足,“NO”表示不可被满足。

Sample Input

2
2
1 2 1
1 2 0
2
1 2 1
2 1 1

Sample Output

NO
YES

HINT

 

 在第一个问题中,约束条件为:x1=x2,x1≠x2。这两个约束条件互相矛盾,因此不可被同时满足。


在第二个问题中,约束条件为:x1=x2,x2=x1。这两个约束条件是等价的,可以被同时满足。

 

1≤n≤1000000

1≤i,j≤1000000000

思路:

并查集很好做,关键是加上离散化
因为数据规模(1e9)很大,超过了数组的上限。但数据据量(1e6) 开数组是刚刚好的
于是我们通过离散排序去重,只把数之间的关系表示出来即可
 

code

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int Mx=1000010;
struct node {
    int x,y;
}ok[Mx],no[Mx];
 
int n,fa[Mx],num[Mx<<1],sated[Mx];
int Find(int x) {
    return x==fa[x]?x:fa[x]=Find(fa[x]);
}
int lisa() {
    int len=0;sated[++len]=num[1];
    for(int i=2;i<=2*n;++i) {
        if(num[i]!=num[i-1]) 
            sated[++len]=num[i];
    }
    return len;
}
 
int serch(int val,int l,int r) {
    int mid=(l+r)>>1;
    if(sated[mid]==val) return mid;
    else if(sated[mid]<val) return serch(val,mid+1,r);
    else return serch(val,l,mid);
}
 
int main() 
{
    int T;
    scanf("%d",&T);
    while(T--) {
        int lok=0,lno=0;
        for(int i=1;i<=Mx;++i) fa[i]=i;
        scanf("%d",&n);
        for(int i=1;i<=n;++i) {
            int u,v,cas;
            scanf("%d%d%d",&u,&v,&cas);
            num[i]=u,num[i+n]=v;
            if(cas) ok[++lok].x=u,ok[lok].y=v;
            else no[++lno].x=u,no[lno].y=v;
        }
        sort(num+1,num+1+n+n);
        int l=lisa();
        for(int i=1;i<=lok;++i) {
            int a=ok[i].x,b=ok[i].y;
            fa[Find(serch(a,1,l))]=Find(serch(b,1,l));
        }
        bool flag=0;
        for(int i=1;i<=lno;++i) {
            int a=no[i].x,b=no[i].y;
            if(Find(serch(a,1,l))==Find(serch(b,1,l))) {
                flag=1;
                break;
            }
        }
        if(flag) printf("NO\n");
        else printf("YES\n");
        memset(ok,0,sizeof(ok));
        memset(no,0,sizeof(no));
    }
    return 0;
}

 

posted @ 2018-10-11 12:31  qseer  阅读(155)  评论(0编辑  收藏  举报