noi.ac NA537 【Graph】

本文探讨了一种解决图论中特定问题的方法,通过将连通块视为根节点进行二分图染色,确保边权限制下的点权合法性。文章详细介绍了算法流程,包括如何处理额外边以确保节点颜色一致性,最终求解最小和最大值。

本来以为过了...然后FST了...

吐槽:nmdGraph为什么不连通...

这题想法其实非常\(na\ddot{\imath}ve\),就是对于一个连通块先钦点一个点为根,颜色是\(1\),考虑到边权限制点权,可以做二分图染色,钦点连通块内的某个形如树形的边的子集是全部合法的,显然一棵树是一定有解的,对于此时的\(\min ,\max\)只需要看根节点的取值范围取\(\min ,\max\),对于图的话显然就是多了一些边,判断多的边两端节点是否同色,如果同色则意味着根节点的权值是唯一确定的,如果不是整数则无解,否则直接赋值重跑一遍计算\(ans\)即可,复杂度\(\mathcal{O}(n+m)\)

因为代码是从FST的改过来的,memset其实会T,但是懒得改了,所以下面代码复杂度是假的,不过不影响正确性

#include<bits/stdc++.h>
#define yes printf("%lld %lld\n",ansa,ansb);exit(0)
#define no printf("NIE\n");exit(0)
#define int long long

using namespace std;

signed ch;

void qread(int &xx){
    xx=0;ch=getchar();
    while(!isdigit(ch)){
        ch=getchar();
    }
    while(isdigit(ch)){
        xx=xx*10+ch-'0';
        ch=getchar();
    }
}

const int N=5e5+5,M=6e6+6;

int n,m,ans,ansa,ansb,p[N],vis[N];

int fir[N],nxt[M],to[M],edge[M],cntedge,col[N],c[N],cnt[3];

int mi[3]={0,0,0x3f3f3f3f},up[3]={0,0,0x3f3f3f3f};

void addedge(int u,int v,int w){
    ++cntedge;to[cntedge]=v;edge[cntedge]=w;nxt[cntedge]=fir[u];fir[u]=cntedge;
}

namespace subtree{
    queue<int>q;
    void bfs(int u){
        for(int now=fir[u],v;now;now=nxt[now]){
            v=to[now];
            if(col[v]){
                continue;
            }
            c[v]=edge[now]-c[u];
            col[v]=3-col[u];
            ++cnt[col[v]];
            ans+=c[v];
            mi[col[v]]=min(mi[col[v]],c[v]);
            up[col[v]]=min(up[col[v]],p[v]-c[v]);
            q.push(v);
        }
    }
    void solve(){
        q.push(1);col[1]=1;++cnt[1];up[1]=p[1];
        while(!q.empty()){
            int u=q.front();q.pop();
            bfs(u);
        }
        if(up[1]+up[2]<0){
            no;
        }
        if(up[1]<0){
            for(int i=1;i<=n;i++){
                col[i]==1?(c[i]+=up[1],ans+=up[1]):(c[i]-=up[1],ans-=up[1]);
            }
            up[2]+=up[1];mi[2]-=up[1];mi[1]+=up[1];up[1]=0;
        }
        if(up[2]<0){
            for(int i=1;i<=n;i++){
                col[i]==2?(c[i]+=up[2],ans+=up[2]):(c[i]-=up[2],ans-=up[2]);
            }
            up[1]+=up[2];mi[1]-=up[2];mi[2]+=up[2];up[2]=0;
        }
        if(mi[1]+up[2]<0||mi[2]+up[1]<0||mi[1]+mi[2]<0){
            no;
        }
        if(mi[1]<0){
            for(int i=1;i<=n;i++){
                col[i]==1?c[i]-=mi[1],ans-=mi[1]:c[i]+=mi[1],ans+=mi[1];
            }
            up[2]+=mi[1];mi[2]+=mi[1];up[1]+=mi[1];mi[1]=0;
        }
        else if(mi[2]<0){
            for(int i=1;i<=n;i++){
                col[i]==2?c[i]-=mi[2],ans-=mi[2]:c[i]+=mi[2],ans+=mi[2];
            }
            up[1]+=mi[2];mi[1]+=mi[2];up[2]+=mi[2];mi[2]=0;
        }
        if(cnt[1]==cnt[2]){
            ansa=ansb=ans;
        }
        else if(cnt[1]<cnt[2]){
            ansa=ans-min(mi[2],up[1])*(cnt[2]-cnt[1]);
            ansb=ans+min(mi[1],up[2])*(cnt[2]-cnt[1]);
        }
        else{
            ansa=ans-min(mi[1],up[2])*(cnt[1]-cnt[2]);
            ansb=ans+min(mi[2],up[1])*(cnt[1]-cnt[2]);
        }
        yes;
    }
}

namespace qwq{
    queue<int>q;
    int s,id=0;bool flag;
    bool check(){
        while(!q.empty()){
            q.pop();
        }
        memset(col,0,sizeof col);
        q.push(s);col[s]=1;ans=c[s];
        while(!q.empty()){
            int u=q.front();q.pop();
            vis[u]=id;
            if(c[u]<0||c[u]>p[u]){
                no;
            }
            for(int now=fir[u],v;now;now=nxt[now]){
                v=to[now];
                if(col[v]){
                    if(c[u]+c[v]!=edge[now]){
                        no;
                    }
                    continue;
                }
                c[v]=edge[now]-c[u];
                col[v]=3-col[u];
                ans+=c[v];
                q.push(v);
            }
        }
        ansa+=ans;ansb+=ans;
        return 1;
    }
    void bfs(int u){
        vis[u]=id;
        for(int now=fir[u],v;now;now=nxt[now]){
            v=to[now];
            if(col[v]){
                if(col[u]^col[v]){
                    if(c[u]+c[v]!=edge[now]){
                        no;
                    }
                }
                else{
                    if(((c[u]+c[v])&1)^(edge[now]&1)){
                        no;
                    }
                    if(col[u]^2){
                        c[s]=(edge[now]-c[u]-c[v])>>1;
                        if(check()){
                            flag=1;return;
                        }
                        else{
                            no;
                        }
                    }
                    else{
                        c[s]=(c[u]+c[v]-edge[now])>>1;
                        if(check()){
                            flag=1;return;
                        }
                        else{
                            no;
                        }
                    }
                }
                continue;
            }
            c[v]=edge[now]-c[u];
            col[v]=3-col[u];
            ++cnt[col[v]];
            ans+=c[v];
            mi[col[v]]=min(mi[col[v]],c[v]);
            up[col[v]]=min(up[col[v]],p[v]-c[v]);
            q.push(v);
        }
    }
    void work(){
        while(!q.empty()){
            q.pop();
        }
        flag=0;
        memset(cnt,0,sizeof cnt);
        up[2]=mi[2]=0x3f3f3f3f;mi[1]=0;
        q.push(s);col[s]=1;++cnt[1];up[1]=p[s];ans=0;
        while(!q.empty()){
            int u=q.front();q.pop();bfs(u);
        }
        if(flag){
            return;
        }
        if(up[1]+up[2]<0){
            no;
        }
        if(up[1]<0){
            for(int i=1;i<=n;i++){
                if(vis[i]!=id){
                    continue;
                }
                col[i]==1?(c[i]+=up[1],ans+=up[1]):(c[i]-=up[1],ans-=up[1]);
            }
            up[2]+=up[1];mi[2]-=up[1];mi[1]+=up[1];up[1]=0;
        }
        if(up[2]<0){
            for(int i=1;i<=n;i++){
                if(vis[i]!=id){
                    continue;
                }
                col[i]==2?(c[i]+=up[2],ans+=up[2]):(c[i]-=up[2],ans-=up[2]);
            }
            up[1]+=up[2];mi[1]-=up[2];mi[2]+=up[2];up[2]=0;
        }
        if(mi[1]+up[2]<0||mi[2]+up[1]<0||mi[1]+mi[2]<0){
            no;
        }
        if(mi[1]<0){
            for(int i=1;i<=n;i++){
                if(vis[i]!=id){
                    continue;
                }
                col[i]==1?c[i]-=mi[1],ans-=mi[1]:c[i]+=mi[1],ans+=mi[1];
            }
            up[2]+=mi[1];mi[2]+=mi[1];up[1]+=mi[1];mi[1]=0;
        }
        else if(mi[2]<0){
            for(int i=1;i<=n;i++){
                if(vis[i]!=id){
                    continue;
                }
                col[i]==2?c[i]-=mi[2],ans-=mi[2]:c[i]+=mi[2],ans+=mi[2];
            }
            up[1]+=mi[2];mi[1]+=mi[2];up[2]+=mi[2];mi[2]=0;
        }
        if(cnt[1]==cnt[2]){
            ansa+=ans;ansb+=ans;
        }
        else if(cnt[1]<cnt[2]){
            ansa+=ans-min(mi[2],up[1])*(cnt[2]-cnt[1]);
            ansb+=ans+min(mi[1],up[2])*(cnt[2]-cnt[1]);
        }
        else{
            ansa+=ans-min(mi[1],up[2])*(cnt[1]-cnt[2]);
            ansb+=ans+min(mi[2],up[1])*(cnt[1]-cnt[2]);
        }
    }
    void solve(){
        for(int i=1;i<=n;i++){
            if(!vis[i]){
                ++id;s=i;
                work();
            }
        }
        yes;
    }
}

signed main(){
    qread(n);qread(m);
    for(int i=1;i<=n;i++){
        qread(p[i]);
    }
    for(int i=1,u,v,w;i<=m;i++){
        qread(u);qread(v);qread(w);addedge(u,v,p[u]+p[v]-w);addedge(v,u,p[u]+p[v]-w);
    }
    if(n==m+1){
        subtree::solve();
    }
    else{
        qwq::solve();
    }
    no;
    return 0;
}

转载于:https://www.cnblogs.com/--BLUESKY007/p/11146569.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值