zoukankan      html  css  js  c++  java
  • 2018CCPCFINAL B Balance of the Force 枚举最大值

    题意

    n个人能选择黑暗面和光明面,选择两个面分别能获得(L_i)(R_i)的力量,有m对人不能选择同一面,问n个人的力量中的最大值-最小值尽可能小为多少。

    (1<=n<=2 imes 10^5)

    (0<=m<=2 imes 10^5)

    (1<=L_i,D_i<=10^9)

    分析

    先二分图染色,每个连通块的最大值和最小值有两种方案,设一共有k个连通块,将所有方案按最大值升序排序,去枚举最大值mx,用线段树维护所有连通块的最小值,若前(i)个方案能构成(k)个连通块,查询(k)个连通块的最小值的最小值(mn),更新答案(ans=min(ans,mx-mn)),若前(i-1)个方案中有第(i)个方案的孪生方案,先删去第(i)个方案的孪生方案的最小值,更新答案后再将当前方案所在的连通块的最小值更新为两种方案较大的最小值。

    Code

    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define pb push_back
    #define lson l,mid,p<<1
    #define rson mid+1,r,p<<1|1
    #define ll long long
    using namespace std;
    const int inf=1e9+10;
    const int mod=1e9+7;
    const int maxn=4e5+10;
    int T,n,m,tot,sz,col[maxn],D[maxn][2],vis[maxn];
    vector<int>g[maxn];
    struct ppo{
        int mn,mx,i;
        bool operator <(const ppo &r) const{
            return mx<r.mx;
        }
    }a[maxn];
    bool dfs(int u,int o){
        col[u]=o;
        a[tot].mn=min(a[tot].mn,D[u][o]);
        a[tot].mx=max(a[tot].mx,D[u][o]);
        a[tot-1].mn=min(a[tot-1].mn,D[u][o^1]);
        a[tot-1].mx=max(a[tot-1].mx,D[u][o^1]);
        for(int x:g[u]){
            if(col[x]==-1){
                if(!dfs(x,o^1)) return false;
            }else if(col[x]!=o^1) return false;
        }
        return true;
    }
    int tr[maxn<<2];
    void bd(int l,int r,int p){
        tr[p]=inf;
        if(l==r) return;
        int mid=l+r>>1;
        bd(lson);bd(rson);
    }
    void up(int x,int l,int r,int p,int k){
        if(l==r) return tr[p]=k,void();
        int mid=l+r>>1;
        if(x<=mid) up(x,lson,k);
        else up(x,rson,k);
        tr[p]=min(tr[p<<1],tr[p<<1|1]);
    }
    int qy(int x,int l,int r,int p){
        if(l==r) return tr[p];
        int mid=l+r>>1;
        if(x<=mid) return qy(x,lson);
        else return qy(x,rson);
    }
    int main(){
        //ios::sync_with_stdio(false);
        //freopen("in","r",stdin);
        scanf("%d",&T);
        for(int cas=1;cas<=T;cas++){
            scanf("%d%d",&n,&m);tot=sz=0;
            for(int i=0;i<=n;i++) g[i].clear(),col[i]=-1,vis[i]=0;
            for(int i=1,a,b;i<=m;i++){
                scanf("%d%d",&a,&b);
                g[a].pb(b);g[b].pb(a);
            }
            for(int i=1;i<=n;i++){
                scanf("%d%d",&D[i][0],&D[i][1]);
            }
            int flag=1;
            for(int i=1;i<=n&&flag;i++) if(col[i]==-1){
                    ++sz;
                    a[++tot]={inf,0,sz};
                    a[++tot]={inf,0,sz};
                    if(!dfs(i,0)) flag=0;
            }
            printf("Case %d: ",cas);
            if(!flag){
                puts("IMPOSSIBLE");
                continue;
            }
            sort(a+1,a+tot+1);
            bd(1,sz,1);
            int sum=0,ans=inf;
            for(int i=1;i<=tot;i++){
                if(!vis[a[i].i]) sum++,vis[a[i].i]=1;
                int tmp=qy(a[i].i,1,sz,1);
                if(sum==sz){
                    up(a[i].i,1,sz,1,a[i].mn);
                    ans=min(ans,a[i].mx-tr[1]);
                }
                if(tmp==inf) tmp=0;
                up(a[i].i,1,sz,1,max(tmp,a[i].mn));
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    Python中的try...except...finally
    JavaScript 实现双向队列并用此来测试一个单词是否为回文
    js 触发 change 事件
    MySQL8 重置改root密码及开放远程访问
    根据数组下标在MongoDB中修改数组元素
    pymongo CursorNotFound错误
    mongodb根据子项中的指标查找最小或最大值
    正则文本过滤时的一些注意事项
    github page更新后不生效
    Xpath同时选取不同属性的元素
  • 原文地址:https://www.cnblogs.com/xyq0220/p/11741548.html
Copyright © 2011-2022 走看看