P1955 程式自動分析 題解

adsd45666發表於2024-10-18

P1955 程式自動分析

一道並查集的裸題,並查集儲存傳遞性,後判斷。主題思路十分簡單,重點在於離散化與離線的處理。

離散化,為什麼會想到離散化呢,觀察資料範圍 \(1<i,j<{10}^9\) ,資料範圍過大,導致陣列不可能開到 \(1e9\) 但是 \(1<n<1e5\) 考慮到每次輸入只有兩個數,若每個數都兩兩不同,則極限大小為 \(2e5\) 在可接受範圍之內,用 \(map\) 來初始化,由於關心的是其兩個數之間的邏輯關係,與其大小並無關係,所以省去按大小排序這一步。

離線處理,並查集維護相等關係,由於相等具有傳遞性 \(a_i=a_j,a_j=a_k則有a_i=a_k\) ,但是不等不具有傳遞性 \(a_i \ne a_j,a_j \ne a_k那麼a_i不一定不等於a_k\) 但由於其要構成矛盾,則先判斷相等與先判斷不等無區別,所以離線操作,先維護相等並查集,再對於不等關係判斷是否矛盾,輸出即可。

#include <bits/stdc++.h>
#define seq(q, w, e) for (int q = w; q <= e; q++)
#define ll long long
using namespace std;
const int maxn = 1e5+10,mod=1e9+7;
struct node{
    int x,y;
    int e;
}a[maxn<<1];
int fa[maxn<<1];
void in_it(int n){
    seq(i,1,2*n){
        fa[i]=i;
        a[i]={0,0,0};
    }
}
int find(int x){
    if(fa[x]==x){
        return x;
    }
    return fa[x]=find(fa[x]);
}
void merge(int x,int y){
    int f1=find(x),f2=find(y);
    if(f1==f2) return;
    fa[f2]=f1;
}
int t,tot,n;
ll x,y;
map<ll,int>mp;
bool cmp(node x,node y){
    return x.e>y.e;
}
bool cmp1=0;
signed main()
{
    // freopen(".in","r",stdin);
    // freopen(".out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin>>t;
    while(t--){
        mp.clear();
        cmp1=0;
        tot=0;
        cin>>n;
        in_it(n);
        seq(i,1,n){
            cin>>x>>y>>a[i].e;
            if(!mp[x]) mp[x]=++tot;
            if(!mp[y]) mp[y]=++tot;
            a[i].x=mp[x];
            a[i].y=mp[y];
        }
        sort(a+1,a+1+n,cmp);
        int num=1;
        while(a[num].e){
            merge(a[num].x,a[num].y);
            num++;
        }
        seq(i,num,n){
            if(find(a[i].x)==find(a[i].y)){
                cmp1=1;
                break;
            }
        }
        if(cmp1){
            cout<<"NO"<<"\n";
        }
        else{
            cout<<"YES"<<"\n";
        }
    }
    return 0;
}

相關文章