D - Unique Path

D - Unique Path

題意

已知有一個圖有n個點m條邊

已知q條線索,以u,v,x的格式給出

x==0x==0,表示u,v之間僅存在一條路徑

否則,表示u,v之間存在多條路經

問,該圖是否存在


思路

考慮計算出若該圖存在,所需的最少邊數和最多邊數

  • 可以先將所有0線索連起來(並查集)

  • 顯然,我們得到多個連通塊,且每一個都是樹

  • 而樹和樹之間是可以相連的,但只可以連一條線(因爲他們之間沒有0關係)

  • 考慮1線索,他需要將孤立點和連通塊串在一個環上

  • 最少的情況:從連通塊和孤立點組成環,且至少有三個點(整個圖要連通

  • 最多的情況:將連通塊和孤立點,全部構成完全圖


代碼

typedef pair<int, int> pii;
const int maxn = 1e5 + 5;
vector<pii> opt[2];
int f[maxn]; //鏈的並查集
bool vis[maxn];
int find(int x)
{
    return x == f[x] ? x : f[x] = find(f[x]);
}
set<int> Set;
int main()
{
    long long nn, mm;
    scanf("%lld%lld", &nn, &mm);
    int q;
    scanf("%d", &q);
    int u, v, x;
    for (int i = 1; i <= q; i++) {
        scanf("%d%d%d", &u, &v, &x);
        opt[x].push_back(make_pair(u, v));
    }
    if (nn == 2) {
        if (opt[0].size() == 1 && q == 1)
            printf("Yes\n");
        else
            printf("No\n");
        return 0;
    }
    for (int i = 0; i < nn; i++)
        f[i] = i;
    for (auto it : opt[0]) {
        vis[it.first] = vis[it.second] = true;
        f[find(it.first)] = find(it.second);
    }
    long long sum = 0, num = 0;
    for (int i = 0; i < nn; i++)
        if (vis[i]) {
            sum++;
            if (find(i) == i)
                num++;
        }
    for (auto it : opt[1]) {
        if (vis[it.first] && vis[it.second]) {
            if (find(it.first) == find(it.second)) {
                printf("No\n");
                return 0;
            }
        }
    }
    long long lone = nn - sum;
    long long m1 = 0, m2 = 0;
    if (opt[1].size() == 0) {
        m1 = sum - num;
        m2 = sum - num + (lone + num) * (lone + num - 1) / 2;
    } else {
        m1 = sum - num + max(3LL, num + lone);
        m2 = (num + lone) * (num + lone - 1) / 2 + sum - num;
    }
    if (mm >= m1 && mm <= m2) {
        printf("Yes\n");
    } else
        printf("No\n");
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章