天天看點

P1955 [NOI2015] 程式自動分析

P1955 [NOI2015] 程式自動分析

https://www.luogu.com.cn/problem/P1955.

離散化+并查集

這道題是一個并查集的經典題目,因為這個題目的資料太大,我們無法直接用f[i]=i來初始化所有的結點,但是輸入的數量隻有n,可以先進行離散化再進行根節點的初始化。

這道題的離散化不需要保持資料的保序性,是以我們可以借助哈希來離散化,也就是STL中的unordered_map來進行離散化。

如果需要保持有序性我們需要進行1.去重(可以用到unique去重函數)2.排序3.二分索引(可以用到lower_bound函數)

#include<iostream>
#include<cmath>
#include<vector>
#include<map>
#include<stack>
#include<queue>
#include<cstring>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<list>
#include<unordered_map>
#include<limits>
#define mem(a,n) memset(a,n,sizeof a)
#define endl '\n'
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define SYS system("pause");
#define For(i, n) for (int i = 0; i< n;i++)
#define FOR(i, n) for (int i = 1; i <= n;i++)
#define rFor(i, n) for (int i = n; i > 0;i--)
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
ll gcd(ll a,ll b){ll d; while(b){ d=b; b=a%b; a=d; } return a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
ll qpow(ll x, ll y) { ll ans = 1; for (; y > 0; y >>= 1) { if (y & 1)ans *= x; x *= x; } return ans;}
ll qpow(ll x, ll y, int MOD) { ll ans = 1; for (; y > 0; y >>= 1) { if (y & 1)ans = ans*x%MOD; x = x*x%MOD; } return ans;}
void exgcd(int a,int b,int &x,int &y){ if(b==0){ x=1;y=0;return; } exgcd(b,a%b,x,y); int temp=y; y=x-(a/b)*y, x=temp; return;}
int downcheck(int l, int r){ while (l < r){ int mid = l + r >> 1; if ("check(mid)") r = mid; else l = mid + 1; } return l;}
int upcheck(int l, int r){ while (l < r){ int mid = l + r + 1 >> 1; if ("check(mid)") l = mid; else r = mid - 1;} return l;}
int doublecheck(int l,int r){ while(r-l>1e-8){ int mid=(l+r)>>1; if("check(mid)") l=mid; else r=mid;} return l; }
#define int long long
const int N = 1e6+10,M=20;
const int inf=0x3f3f3f3f;
const int mod=1e9+7; 
const double pi = acos(-1.0);
int n,t,m;
int f[N];
int cnt = 0;
unordered_map<int, int> mp;      //進行離散化記錄的哈希表
int x1[N], x2[N], vis[N];
int find(int x){
    if(f[x]==x)
        return x;
    return f[x] = find(f[x]);
}
void join(int x,int y){
    int fx = find(x), fy = find(y);
    if(fx!=fy)   f[fx] = fy;
}
int merge(int x){    //離散化
      if(mp.count(x)==0) mp[x] = ++cnt;   
      return mp[x];
}
signed main(){{}
    //IOS
    cin >> t;
    while(t--){
        mp.clear();
        cnt = 0;
        int y1, y2;
        cin >> n;
        FOR(i, 2*n)    f[i] = i;   //注意初始化結點數為2n,因為可能最多的數為2n
        FOR(i, n){
            cin >> y1 >> y2 >> vis[i];
            x1[i] = merge(y1);
            x2[i] = merge(y2);    //存入離散化後的值
        }
        FOR(i,n){
            if(vis[i]==1){
                join(x1[i], x2[i]);      //判斷相等就是直接合并集合
            }
        }
        bool flag = 1;
        FOR(i,n){
            if(vis[i]==0){               //判斷不等就是看看是否在同個集合
                if(find(x1[i])==find(x2[i])){
                    flag = 0;
                    break;
                }
            }
        }
        if(flag)
            cout << "YES" << endl;
        else
            cout << "NO" << endl;
    }
    SYS
    return 0;
}
           

繼續閱讀