【NOI2015】BZOJ4195程式自動分析(並查集+離散化)
阿新 • • 發佈:2018-12-13
演算法:離散化+並查集
難度:NOIP
首先,易證(資料範圍:10^9那麼大,如果開一個10^9的fa陣列的話,空間肯定超限),此題需要離散化----->方法
all in all,離散化有三步:
1.排序
2.去重(可以用到unique去重函式)
3.二分索引(可以用到lower_bound函式)
離散化之後,將e=1的情況(等式)直接新增到並查集中,之後列舉檢驗不等式是否成立即可,對於它約束的兩個變數,如果在一個集合裡面,那就不可能滿足!如不相等的約束條件都滿足,那就YES。
注意:
- fa陣列要開2*n辣麼大(因為離散化後,有辣麼多的數數呀)
- 記得給fa陣列賦初值
- 記得要請陣列
- unique之前一定要先排序,因為它處理的是相鄰元素的重複元素。---> 詳解
(彷彿一點也不詳)
程式碼如下:
#include <cstdio> #include <iostream> #include <algorithm> #include <cstdlib> #include <cmath> #include <cstring> #define ll long long #define N 100005 using namespace std; struct node { int x,y,e; }a[N]; int lsh[N<<1],fa[N<<1];//因為離散化之後的大小是2*n int cmp(node a,node b) { return a.e>b.e; } int findf(int x) { if(x==fa[x]) return x; return fa[x]=findf(fa[x]); } int main() { int T; scanf("%d",&T); while(T--) { int cnt=0; memset(a,0,sizeof(a)); memset(lsh,0,sizeof(lsh)); memset(fa,0,sizeof(fa)); int n; scanf("%d",&n); for(int i = 1;i <= n;i++) { scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].e); lsh[++cnt]=a[i].x; lsh[++cnt]=a[i].y; } sort(lsh+1,lsh+1+cnt); int uni=unique(lsh+1,lsh+1+cnt)-lsh;//unique之前要先排序,因為它處理的是相鄰元素的重複元素 for(int i = 1;i <= n;i++) { a[i].x=lower_bound(lsh,lsh+uni,a[i].x)-lsh; a[i].y=lower_bound(lsh,lsh+uni,a[i].y)-lsh; } for(int i = 1;i <= uni;i++) { fa[i]=i; } sort(a+1,a+n+1,cmp); int flag=1; for(int i = 1;i <= n;i++) { int r1=findf(a[i].x); int r2=findf(a[i].y); if(a[i].e) { fa[r1]=r2; }else if(r1==r2) { puts("NO"); flag=0; break; } } if(flag) puts("YES"); } return 0 ; }