在實現程序自動分析的過程當中,經常須要斷定一些約束條件是否能被同時知足。node
考慮一個約束知足問題的簡化版本:假設x1,x2,x3...表明程序中出現的變量,給定n個形如xi=xj或xi≠xj的變量相等/不等的約束條件,請斷定是否能夠分別爲每個變量賦予恰當的值,使得上述全部約束條件同時被知足。例如,一個問題中的約束條件爲:x1=x2,x2=x3,x3=x4,x4≠x1,這些約束條件顯然是不可能同時被知足的,所以這個問題應斷定爲不可被知足。c++
如今給出一些約束知足問題,請分別對它們進行斷定。git
輸入格式:數組
從文件prog.in中讀入數據。ide
輸入文件的第1行包含1個正整數t,表示須要斷定的問題個數。注意這些問題之間是相互獨立的。函數
對於每一個問題,包含若干行:spa
第1行包含1個正整數n,表示該問題中須要被知足的約束條件個數。接下來n行,每行包括3個整數i,j,e,描述1個相等/不等的約束條件,相鄰整數之間用單個空格隔開。若e=1,則該約束條件爲xi=xj;若�e=0,則該約束條件爲xi≠xj;code
輸出格式:blog
輸出到文件 prog.out 中。
輸出文件包括t行。
輸出文件的第 k行輸出一個字符串「 YES」 或者「 NO」(不包含引號,字母所有大寫),「 YES」 表示輸入中的第k個問題斷定爲能夠被知足,「 NO」 表示不可被知足。
上次寫完並查集後孟神又讓寫的並查集題,題目理解不難,只要先將全部須要判等的約束條件作完,那麼當約束條件爲0時,咱們只須要查詢他們是否被約束過判等的條件,和並查集維護依賴關係的性質很是類似,因此咱們能夠用並查集來寫這個題;
但等等;妹主席說過不看數據範圍寫題就是在對本身耍流氓;
那咱們就能夠寫個離散化啦,感謝Millope教個人離散化;
排序+去重+二分索引(lower—bound函數);
可是須要注意要將全部的約束相等條件先作完,因此咱們將約束爲1的排在0以前;
還須要注意的每次咱們要將father數組清零,不然下一次find能夠會出錯;
#include<bits/stdc++.h> using namespace std; #define N 200010 template<typename T>inline void read(T &x) { x=0;T f=1,ch=getchar(); while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} x*=f; } int father[N],n,m,flag; inline int find(int x){return father[x]==x?x:father[x]=find(father[x]);} struct node { int x, y, z; }a[N]; bool cmp(node a, node b){return a.z>b.z;} int sizeb=0,b[N]; int main() { read(n); for(int i=1;i<=n;i++) { flag=1;sizeb=0; memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); memset(father,0,sizeof(father)); read(m); for(int j=1;j<=m;j++) { read(a[j].x);read(a[j].y);read(a[j].z); b[++sizeb]=a[j].x; b[++sizeb]=a[j].y; } sort(b+1,b+sizeb+1); sizeb=unique(b+1,b+sizeb+1)-b-1; for(int i=1;i<=m;++i) { a[i].x=lower_bound(b+1,b+sizeb+1,a[i].x)-b; a[i].y=lower_bound(b+1,b+sizeb+1,a[i].y)-b; } for(int i=1;i<=sizeb;i++) { father[i]=i; } sort(a+1,a+m+1,cmp); for(int i=1;i<=m;i++) { int p=find(a[i].x),q=find(a[i].y); if(a[i].z) father[p]=q; else if(p==q) { printf("NO\n"); flag=0; break; } } if(flag) printf("YES\n"); } return 0; }