[NOI 2015] The program automatically analyzes disjoint-set with discrete processing

Title Description

During the implementation of the program of the automatic analysis, it is often necessary to determine whether the number of constraints can be satisfied simultaneously.

Consider a simplified version of a constraint satisfaction problem: Suppose x1, x2, x3, ... represent program variables appearing, given n of the form xi = xj xi ≠ xj variables or equal / unequal constraint criteria, it is determined whether It may be given separately for each variable appropriate value, so that all the above constraints are simultaneously satisfied. For example, a constraint problem is: x1 = x2, x2 = x3 , x3 = x4, x1 ≠ x4, these constraints can not obviously be met simultaneously, so this problem can not be determined to be satisfied.
Now give some constraint satisfaction problems, they were to be judged.

Entry

The input file comprises a first line a positive integer t, it indicates the number of issues to be determined. Note that these are separate issues between.

For each question, comprising a plurality of lines:
Line 1 contains a positive integer n, the number of constraints that need to issue conditions are satisfied.
Subsequently n rows, each row comprising three integers i, j, e, described an equal / unequal constraints, separated by a single space between adjacent integers. If e = 1, the constraint is xj xi =; if e = 0, then the constraint is xi ≠ xj.

Export

Output file including t rows.

K-th row of the output file output a character string "YES" or "NO" (without the quotes, all capital letters), "YES" denotes the k-th input is determined that the problem can be satisfied, "NO" indicates not be Satisfy.

Test input

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

Test output

NO
YES

prompt

In the first problem, the constraints are: x1 = x2, x1 ≠ x2. These two constraints contradict each other, and therefore can not be simultaneously satisfied.

In the second problem, the constraints are: x1 = x2, x2 = x1. These two constraints are equivalent, it can be simultaneously satisfied.

1≤n≤1000000

1≤i,j≤1000000000

Topic analysis

For this question, the purpose is to determine whether the program meets all of the input, because only the similarities and differences between two kinds of relationships, then we can start to deal with all of the same relationship with the same number of disjoint-set to maintain a disjoint collection Alternatively disjoint sets, and then process a different number of, all the different numbers upon different numbers contradiction occurs in the same set, the output of NO can, traversed to find it to belong to a different set of output YES, the present title Note that the input number is larger, the need for discrete processing, the array is not directly open to

important point

  1. And check on the establishment of the set, this problem due to the large amount of data, it is necessary to use a compression path, the annotation is not part of the code employed when compression path, a path compression set before the object can be merged with another set is a trees depth of only 1 tree, thus reducing the consumption of the query part (when large volumes of data more obvious)
int find(int x){
    if(p[x] == x) return x;
    else{
        p[x] = find(p[x]);
    }
    return p[x];    
//  while(p[x] != x){
//      x = p[x];
//  }
//  return x;
}
  1. About C ++ STL is unique () function, its role is to complete a sorted array, to achieve "merge" the same number of adjacent, why it merged with the quotation marks? In fact, the combined length of the array does not change, it is the continuous process of merging the back of the front cover element repeating elements (not specifically be explained), the unique operation performed when an array, typically takes two arguments, the array first address and end address, and its return value is an array after completion of the last check bit re-ordered reference to a +1, that is to say through the array 1,1,2,2,4,5,5,6 unique ( a, then a + 8) 1,2,4,5,6,5,5,6 array becomes only the first five are ordered, and int t = unique (a, a + 8) deposited a is [5] a reference, so if several are specifically conceivable Usually we write int t = unique (a, a + 8) - a; that is naturally t 5, the following is the code
#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;

int main(){
    int a[] = {1, 1, 2, 2, 4, 5, 5, 6};
    int t = unique(a, a + 8) - a;
    cout<<t<<endl;
    cout<<a[t]<<endl;
    for(int i = 0; i <= 7; i++){
        cout<<a[i]<<endl;
    }
    return 0;
}
  1. On the use of lower_bound () function, which is an efficient method for binary search an array of first occurrence of a number of references, it accepts three parameters, the first address of the array, the array end address, the number of values ​​to be queried, generally, we will check out the result of subtracting the array name, then get a position in the array subscript position i is the number to find the first occurrence of
 i = lower_bound(a + 1, a + n + 1, number) - a;
  1. Discrete: Because the amount of data i, j great, but up to one million pairs of input, obviously there are up to two million different numbers, we can build a two million large arrays to store all of this input i, j (although they themselves may but much more than two million on this array actually no problem)

The title Code

#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;

const int N = 1000005;
int p[N<<1];
int m[N<<1];
int x[N];
int y[N];
int type[N];
int n, cnt, num;
struct Node{            //结构体是用于存放那些不同的数对的i j的第一次在数组中出现的位置 
    int x, y;
}k[N<<1];

void merge(){           //合并重复元素,实际上是覆盖操作,数组长度未发生变化,temp存放最后一个有序位置的索引(因为-m-1) 
    sort(m + 1, m + num + 1);
    int temp = unique(m + 1, m + num + 1) - m - 1;
    for(int i = 1; i <= n; i++){
        x[i] = lower_bound(m + 1, m + temp + 1, x[i]) - m;  //lowerbound()前两个参数的闭区间和开区间 
        y[i] = lower_bound(m + 1, m + temp + 1, y[i]) - m;  //执行完成后x[i]存放m数组中第一次出现x[i]的位置 
    }
}

int find(int x){
    if(p[x] == x) return x;
    else{
        p[x] = find(p[x]);
    }
    return p[x];    
//  while(p[x] != x){
//      x = p[x];
//  }
//  return x;
}

void Union(int x, int y){
    int fx = find(x);
    int fy = find(y);
    if(fx != fy) p[fy] = fx;
}

int main(){
    int t;
    scanf("%d", &t);
    while(t--){
        scanf("%d", &n);
        cnt = 0;
        num = 0;
        for(int i = 1; i <= n; i++){                    //对输入的n组输入进行2*n的离散化处理 
            scanf("%d%d%d", &x[i], &y[i], &type[i]);
            m[++num] = x[i];
            m[++num] = y[i];
        }
        for(int i = 1; i <= num; i++) p[i] = i;         //p数组存放根 
        merge();
        for(int i = 1; i <= n; i++){
            if(type[i] == 1){
                Union(x[i], y[i]);              //type == 1时 将根合并同时路径压缩,这里要注意,x[i] y[i] 
            }else{                              //存放的是第一次出现位置,只有这样才能在2000000空间中查询1000000000大的数 
                k[++cnt].x = x[i];              //k结构体数组存放type == 0时数对x[i],y[i]第一次在数组m中出现的位置 
                k[cnt].y = y[i];                
            }
        }
        int flag = 0;
        for(int i = 1; i <= cnt; i++){
            int fx = find(k[i].x);
            int fy = find(k[i].y);
            if(fx == fy){                       //如果根相同 则说明相等 矛盾 
                flag = 1;
                printf("NO\n");
                break;
            }
        }
        if(flag == 0){
            printf("YES\n");
        }
    }
    return 0;
}

Guess you like

Origin www.cnblogs.com/findview/p/11294833.html