1. 程式人生 > >luogu1955 [NOI2015] 程序自動分析

luogu1955 [NOI2015] 程序自動分析

bool def 排序 sorted 存在 程序 IT clas main

題目大意

  假設x1,x2,x3...代表程序中出現的變量,給定n個形如xi=xj或xi≠xj的變量相等/不等的約束條件,請判定是否可以分別為每一個變量賦予恰當的值,使得上述所有約束條件同時被滿足。i,j<=1000000000, n<=1000000

思路

  如果把所有相等的變量納為一個或幾個集合,那麽輸出yes當且僅當同一個相等集合中不存在一對xi,xj被要求不相等。集合→並查集。i,j,n的範圍→離散化。

離散化的標準做法

功能

  將離散的數據壓縮到一個有限的區間處理。具體可以為輸入一個數的下標,輸出該下標的排名。

實現

  將原始下標排序,得到一個下標為原始下標排名順序、值為原始下標的數組。然後我們就可以運用LowerBound二分由原始下標找到其在原數組中的位置了。

註意事項

並查集

  • 一開始所有節點的Father都是自己。
  • Join兩個節點是將一個節點的Root的Father設為另一個節點的Root,而不是將節點的Father設為另一個節點。

整體

  • 如果只想得到70分的話,註意下標範圍是多於N的,所以並查集中的N都應當設為1000000。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdlib>
using namespace std;

const int MAX_N = 200010;

struct Discret
{
private:
    int SortedA[MAX_N];
    int Rank[MAX_N];
    int N;

    int LowerBound(int *a, int l, int r, int k)
    {
        while (l < r)
        {
            int mid = (l + r) / 2;
            if (k <= SortedA[mid])
                r = mid;
            else
                l = mid + 1;
        }
        return l;
    }

public:
    void Init(int n, int *a)
    {
        N = n;
        for (int i = 1; i <= n; i++)
            SortedA[i] = a[i];
        sort(SortedA + 1, SortedA + n + 1);

        int prevVal = 0, rankCnt = 0;
        for (int i = 1; i <= n; i++)
        {
            if (SortedA[i] != prevVal)
            {
                Rank[i] = ++rankCnt;
                prevVal = SortedA[i];
            }
            else
                Rank[i] = rankCnt;
        }
    }

    int GetRank(int val)
    {
        return Rank[LowerBound(SortedA, 1, N, val)];
    }

}List;

struct UnionFind
{
private:
    struct Node
    {
        Node *Father;
    }_nodes[MAX_N];

    Node *GetRoot(Node *cur)
    {
        return cur->Father == cur ? cur : cur->Father = GetRoot(cur->Father);
    }

public:
    void Init(int n)
    {
        for (int i = 1; i <= n; i++)
            _nodes[i].Father = _nodes + i;
    }

    bool SameRoot(int a, int b)
    {
        Node *root1 = GetRoot(_nodes + a);
        Node *root2 = GetRoot(_nodes + b);
        return root1 == root2;
    }

    void Join(int a, int b)
    {
        GetRoot(_nodes + a)->Father = GetRoot(_nodes + b);
    }
}G;

int main()
{
#ifdef _DEBUG
    freopen("c:\\noi\\source\\input.txt", "r", stdin);
#endif
    static vector< pair<int, int> > equal, nequal;
    static int OrgVal[MAX_N];
    int caseCnt;
    scanf("%d", &caseCnt);
    while (caseCnt--)
    {
        equal.clear();
        nequal.clear();

        int n;
        scanf("%d", &n);
        for (int i = 1; i <= n; i++)
        {
            int x1, x2, isEqual;
            scanf("%d%d%d", &x1, &x2, &isEqual);

            if (isEqual)
                equal.push_back(pair<int, int>(x1, x2));
            else
                nequal.push_back(pair<int, int>(x1, x2));

            OrgVal[i * 2 - 1] = x1;
            OrgVal[i * 2] = x2;
        }
        List.Init(n * 2, OrgVal);
        G.Init(n * 2);
        for (int i = 0; i < equal.size(); i++)
        {
            int rank1 = List.GetRank(equal[i].first), rank2 = List.GetRank(equal[i].second);
            if (!G.SameRoot(rank1, rank2))
                G.Join(rank1, rank2);
        }

        bool Ok = true;
        for (int i = 0; i<nequal.size(); i++)
        {
            int rank1 = List.GetRank(nequal[i].first), rank2 = List.GetRank(nequal[i].second);
            if (G.SameRoot(rank1, rank2))
            {
                Ok = false;
                break;
            }
        }
        if (Ok)
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}

  

luogu1955 [NOI2015] 程序自動分析