• 洛谷P6185 [NOI Online #1 提高组]序列(二分图+并查集+思维)


    题目链接:https://www.luogu.com.cn/problem/P6185

    为啥这题在洛谷难度标记只是个蓝题,我觉得明明有紫题的水准了吧,但这个题很不错,一开始的时候我没想出来转化成图论模型来做,就觉得这是一个很高大上的难题。但是看了别人写的题解之后,发现其实是一个非常不错的二分图带思维的题。

    解法:

    ①问题相当于有一个序列ci=aibi,要进行若干次操作使得ci每一项都为0

    ②对于操作2 u v,我们在u和v之间连接一个无向边,形成一个联通块,把联通块通过并查集标记该连通块序号。我们发现在这个操作之中,每个u和v之间的数值都可以互相转化,但是仔细一想会发现这个规律,该连通块内数值的和恒不变。那OK,我们就把这个连通块缩点,该点的权值为该连通块内所有节点的和。

    ③处理完操作2了,我们就要处理操作1 u v了。通过之前操作,我们把u=id[u],v=id[v]。操作1是生死与共,即两边u和v同时±1,那我们继续想着把u和v连边建立新的无向图,然后想想操作1,就是无向图内所有节点总和±2对吧。那我们回归到①这一块,要让每个ci都为0,那么显然所有节点和就是0了。所以判断有无最终解的一个前提是所有节点的sum是不是为偶数,如果不是偶数那就直接掰掰;然后我们考虑是不是二分图。因为如果是二分图的话,其实就是把所有节点分成了2部分,因为我之前提过是同生共死的关系,所以左部分和与右部分和之间的差值恒不变。而每一个部分之间又可以内部转化,所以呢可想而知如果左部分和!=右部分和,那么ci的和永远不可能为0,所以另一个判断条件在二分图的情况下,左部分和与右部分和相等;接下来想不是二分图的情况了,之前说过内部转化(本质其实就是2点之间距离为偶数的点之间可以通过中间点架桥来实现类似于操作2的一边+一边-的情况),既然不是二分图就无所谓什么左部分右部分了,直接来呗,所有点都可以转化嘛。那么我们想把n-1个点全部转化成0,把sum集中到一个点上(之前说过前提是sum为偶数),具体例子你们自己想,很容易想出。我提供一个: ①-②,②-③,③-①,①=100,②=③=0。那么就是把①变成50,②变成-50;①再变成0,③再变成-50;②和③同时变为0,那就转化完了。懂了吧?所以对于不是二分图的情况来说,只要sum为偶数就行.

    AC代码:

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,n) for(int i=a;i<=n;i++)
    #define per(i,n,a) for(int i=n;i>=a;i--)
    #define endl '
    '
    #define eps 0.000000001
    #define pb push_back
    #define mem(a,b) memset(a,b,sizeof(a))
    #define IO ios::sync_with_stdio(false);cin.tie(0);
    using namespace std;
    const int INF=0x3f3f3f3f;
    const ll inf=0x3f3f3f3f3f3f3f3f;
    const int mod=1e9+7;
    const int maxn=1e5+5;
    int n,m,a[maxn],b[maxn];
    int p[maxn],q[maxn],id[maxn],fa[maxn],cnt;
    ll val[maxn],sum,sum1,sum2;
    vector<int> G[maxn];int col[maxn],flag;
    int find(int x){
        while(x!=fa[x]) x=fa[x]=fa[fa[x]];
        return x;
    }
    void dfs(int x){
        if(col[x]==1)sum1+=val[x];
        else sum2+=val[x];
        sum+=val[x];
        for(auto v:G[x]){
            if(col[v]){
                if(col[v]==col[x]) flag=0;
            }else{
                col[v]=3-col[x];
                dfs(v);
            }
        }
    }
    int main(){
        int T;scanf("%d",&T);
        while(T--){
            scanf("%d%d",&n,&m);
            rep(i,1,n) scanf("%d",&a[i]),fa[i]=i;
            rep(i,1,n) scanf("%d",&b[i]),a[i]-=b[i];
            int ct=0;
            rep(i,1,m){
                int o,a,b;scanf("%d%d%d",&o,&a,&b);
                if(o==1){p[++ct]=a;q[ct]=b;}
                else{
                    int u=find(a),v=find(b);
                    if(u!=v) fa[u]=v;
                }
            }
            cnt=0;
            rep(i,1,n){
                if(find(i)==i) id[i]=++cnt;
            }
            rep(i,1,cnt){
                G[i].clear();col[i]=0;val[i]=0;
            }
            rep(i,1,n){
                val[id[find(i)]]+=a[i];
            }
            rep(i,1,ct){
                int u=id[find(p[i])],v=id[find(q[i])];
                G[u].pb(v);G[v].pb(u);
            }
            bool yes=1;
            rep(i,1,cnt){
                if(!col[i]){
                    flag=1;sum=sum1=sum2=0;
                    col[i]=1;
                    dfs(i);
                    if(sum%2!=0){
                        yes=0;break;
                    }
                    if(flag&&sum1!=sum2){
                        yes=0;break;
                    }
                }
            }
            if(yes)puts("YES");
            else puts("NO");
        }
    }
    View Code
  • 相关阅读:
    BZOJ 3262 cdq分治 OR 树套树
    Weekly Contest 132
    1007. Minimum Domino Rotations For Equal Row
    1002. Find Common Characters
    974. Subarray Sums Divisible by K
    926. Flip String to Monotone Increasing
    918. Maximum Sum Circular Subarray
    914. X of a Kind in a Deck of Cards
    907. Sum of Subarray Minimums
    900. RLE Iterator
  • 原文地址:https://www.cnblogs.com/Anonytt/p/13354550.html
Copyright © 2020-2023  润新知