BZOJ 4195 程式自動分析【並查集+離散化】
阿新 • • 發佈:2018-12-11
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
題解:資料範圍比較大,必須先進行離散化處理。然後就是並查集了。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define ll long long using namespace std; const int maxn = 1000000; struct node { int i, j; int e; }a[maxn]; int fa[maxn], b[maxn<<1|1]; int get(int x){ if(x == fa[x]) return x; return fa[x] = get(fa[x]); } void Merge(int x, int y){ fa[get(x)] = get(y); } int main() { int t, n; scanf("%d", &t); while(t--) { int id = 0; memset(fa, -1, sizeof fa); scanf("%d", &n); int flag = 1; for(int i = 1; i <= n; i++) { scanf("%d %d %d", &a[i].i, &a[i].j, &a[i].e); b[++id] = a[i].i, b[++id] = a[i].j; } sort(b+1, b+id+1); //tot = unique(b, b+id); for(int i = 1; i <= id; i++) fa[i] = i; for(int i = 1; i <= n; i++){ if(a[i].e == 1){ int x = lower_bound(b, b+id, a[i].i) - b; int y = lower_bound(b, b+id, a[i].j) - b; Merge(x, y); } } for(int i = 1; i <= n; i++){ if(!a[i].e){ int x = lower_bound(b, b+id, a[i].i) - b; int y = lower_bound(b, b+id, a[i].j) - b; if(get(x) == get(y)){ flag = 0; break; } } } if(flag) printf("YES\n"); else printf("NO\n"); } return 0; }