程序笔记   发布时间:2022-07-18  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了P6185 [NOI Online #1 提高组] 序列 题解大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

一、题目:

洛谷原题

二、思路:

这道题是一道蓝题,我都没想出来ὢ5;。我真的是菜到家了,今年的 NOI 不打铁都奇怪。

首先可以发现,操作 2 具有可传递性。若 ((a,b)) 可以有操作 2,((b,C)) 也可以有操作 2,那么 ((a,C)) 也可以等价地相当于有操作 2。所以我们可以将操作 1 和 2 看做两种无向边,使用并查集将第二种边的连通块缩成一个点。缩完点之后的图就只剩了第一种边。(注意,缩完点后的图是有自环的。)

设缩完点后的点权 (sumlimits b_x-a_X)

又可以发现,若第二种边形成了一个奇环,那么就可以在任意两点同时 +1 或 -1,也可以在任意两点一加一减。所以,如果环的点权之和为偶数,就可以完成目标;若第二种边形成了一个偶环,则可以看成是二分图。二分图的左部点的点权和和右部点的点权和之差是个定值,所以如果两部的点权和相等,就可以完成目标。(特别地,自环是奇环,所以自环并不影响正确性。)

三、代码:

#include <iostream>
#include <cstdio>
#include <cString>
#include <vector>

using namespace std;
#define FILEIN(s) freopen(s, "r", stdin)
#define FILeoUT(s) freopen(s, "w", stdout)
#define mem(s, v) memset(s, v, sizeof s)

inlinE int read(void) {
    int x = 0, f = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    return f * x;
}

const int MAXN = 1e5 + 5;

int n, m, a[MAXN], b[MAXN], fa[MAXN], idx, c[MAXN];
long long sum[MAXN], sumc[3];
pair<int, int>optb[MAXN];
vector<int>linker[MAXN];

int find(int X) {
    if (x == fa[x]) return x;
    return fa[x] = find(fa[x]);
}

inline void merge(int x, int y) {
    x = find(X); y = find(y);
    if (x != y) fa[x] = y; 
}

bool dfs(int x, int col) {
    c[x] = col;
    bool ok = true;
    sumc[col] += sum[x];
    for (auto &y : linker[x]) {
        if (c[y] == col) ok = false;
        if (!c[y] && !dfs(y, 3 - col)) ok = false;  
    }
    return ok;
}

int main() {
    int T = read();
    while (T --) {
        
        n = read(); m = read();

        for (int i = 1; i <= n; ++ i) sum[i] = sumc[i] = c[i] = 0, linker[i].clear(), fa[i] = i;
        idx = 0;

        for (int i = 1; i <= n; ++ i) a[i] = read();
        for (int i = 1; i <= n; ++ i) b[i] = read();

        for (int i = 1; i <= m; ++ i) {
            int t = read(), x = read(), y = read();
            if (t == 2) merge(x, y);
            else optb[++ idx] = { x, y };
        } 

        for (int x = 1; x <= n; ++ X) {
            sum[find(X)] += b[x] - a[x];
        }

        for (int i = 1; i <= idx; ++ i) {
            int x = optb[i].first, y = optb[i].second;
            linker[find(X)].push_BACk(find(y));
            linker[find(y)].push_BACk(find(X));
        }

        bool flag = true;
        for (int x = 1; x <= n; ++ X) {
            if (!c[x] && find(X) == X) {
                sumc[1] = sumc[2] = 0;
                bool ok = dfs(x, 1);
                if (ok) {
                    if (sumc[1] != sumc[2]) { flag = false; break; }
                }
                else {
                    if ((sumc[1] + sumc[2]) & 1) { flag = false; break; }
                }
            }
        }
        if (flag) puts("YES");
        else puts("NO");
        
    }
    return 0;
}

P6185 [NOI Online #1 提高组] 序列 题解

大佬总结

以上是大佬教程为你收集整理的P6185 [NOI Online #1 提高组] 序列 题解全部内容,希望文章能够帮你解决P6185 [NOI Online #1 提高组] 序列 题解所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。