B - Balance of the Force 二分图染色+线段树+枚举

                                                                    B. Balance of the Force

time limit per test

4 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

A long time ago in a galaxy far, far away, there was a group of knights who mastered the ancient power - the Force. To bring order and balance to the universe, the Force is divided into two categories that conflict with each other: the Jedi, who acts on the light side of the Force through non-attachment and arbitration, and the Sith, who uses the dark side through fear and aggression.

There were NN knights who mastered the Force. Each knight could join either the light side or the dark side. When joining the light side, the knight possesses LiLi Force; when joining the dark side, the knight possesses DiDi Force.

To maintain order and balance of the universe, the knights wanted to make the Force difference between the most powerful knight and the weakest knight as small as possible. To make things even tougher, some knights did not get along well, and they refused to join on the same side.

Input

The first line of the input gives the number of test cases, TT (1≤T≤201≤T≤20). TT test cases follow.

For each test case, the first line contains two integers NN (1≤N≤2×1051≤N≤2×105) and MM (0≤M≤2×1050≤M≤2×105), where NN is the number of knights and MM is the number of knight pairs that didn't get along well.

The next MM lines each contains two integers xx and yy (1≤x≠y≤N1≤x≠y≤N), describing knight xx and knight yy didn't get along well.

The following NN lines each contains two integers, LiLi and DiDi (1≤Li,Di≤1091≤Li,Di≤109), representing the Force when the knight joined the light side and the dark side.

Output

For each test case, output one line containing "Case x: y", where x is the test case number (starting from 11) and y is the minimum difference between the strongest knight and weakest knight, or "IMPOSSIBLE" (quotes for clarify) if it's impossible for the knights to pick side without violating the given constraints.

Example

input

Copy

3
3 1
1 2
1 2
3 4
5 6
4 3
1 2
2 3
1 3
1 2
3 4
5 6
7 8
2 0
2 1
3 5

output

Copy

Case 1: 3
Case 2: IMPOSSIBLE
Case 3: 1

Note

For the case 1, let knight 1 join the dark side then let knight 2 and 3 join the light side, the power of each knight are 2, 3 and 5, and the answer should be 5−2=35−2=3.

For the case 3, let both knights join the light side, the answer becomes 3−2=13−2=1.

传送门

题意:给出n个人,总共两个阵营,约束有m对人不能出现在同意阵营。每个人都有加入不同阵营带来的不同能力值。问每个人选好阵营后,最大能力的减去最小能力的值的最小是多少。

题解:把约束分成若干个联通块,每个连通块会有两种值。记录每次最大值,排个序。从大到小遍历最大值。每次都用线段树维护最小值的最大,使得差值尽量小。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <cstring>
#define lc d<<1
#define rc d<<1|1
#define mid ((l+r)>>1)
using namespace std;
#define ll long long
const int maxn=2e5+50;
vector <int> ve[maxn];
int tot, n, m, num;
int l[maxn], d[maxn], col[maxn], vis[maxn];
int maxx[maxn][5], minn[maxn][5];

struct zzh{
    int mxva, miva, opmiva, id;
    bool operator < (const zzh &t)const{
        return mxva > t.mxva;
    }
}mxst[maxn*2];
struct tree{
    int mi;
    tree(){}
    tree(int mm):mi(mm){}
    tree operator + (const tree &t){
        return tree(min(t.mi, mi));
    }
}T[maxn*4];
void init(){
    memset(col, 0, sizeof(col));
    memset(vis, 0, sizeof(vis));
    memset(maxx, 0, sizeof(maxx));
    memset(minn, 0x3f3f3f3f, sizeof(minn));
    for(int i=1; i<=n; i++)
        ve[i].clear();
    tot = 0;
}

void pushup(int d){
    T[d]=T[lc]+T[rc];
}
void build(int l, int r, int d){
    if(l==r){
        T[d].mi=max(minn[l][1], minn[l][2]);
        return;
    }
    build(l, mid, d<<1);
    build(mid+1, r, d<<1|1);
    pushup(d);
}
void update(int l, int r, int d, int L, int x){
    if(l==r){
        T[d].mi = x;
        return;
    }
    if(mid < L) update(mid+1, r, rc, L, x);
    else update(l, mid, lc, L, x);
    pushup(d);
    return;
}
tree query(int l, int r, int d, int x){
    if(l==r) return T[d];
    if(mid < x) return query(mid+1, r, rc, x);
    return query(l, mid, lc, x);
}
bool ff;
void dfs(int x, int color){
    if(color==1){
        maxx[tot][1]=max(maxx[tot][1], l[x]);
        minn[tot][1]=min(minn[tot][1], d[x]);
        maxx[tot][2]=max(maxx[tot][2], d[x]);
        minn[tot][2]=min(minn[tot][2], l[x]);
    }
    else{
        maxx[tot][1]=max(maxx[tot][1], d[x]);
        minn[tot][1]=min(minn[tot][1], l[x]);
        maxx[tot][2]=max(maxx[tot][2], l[x]);
        minn[tot][2]=min(minn[tot][2], d[x]);
    }
    col[x]=color;
    for(int i=0, y; i<ve[x].size(); i++){
        y=ve[x][i];
        if(col[y]==col[x]){
             ff=1;
             break;
        }
        if(!col[y]){
            dfs(y, -color);
        }
    }
    return ;
}
int main(){
    int t;
    scanf("%d",&t);
    for(int o=1; o<=t; o++){
        printf("Case %d: ",o);
        init();
        num=0;
        scanf("%d%d",&n,&m);
        for(int i=1, x, y; i<=m; i++){
            scanf("%d%d",&x,&y);
            ve[x].push_back(y);
            ve[y].push_back(x);
        }
        ff = 0;
        for(int i=1; i<=n; i++)
            scanf("%d%d",&l[i], &d[i]);
        for(int i=1; i<=n; i++) {
            if(!col[i]) {
                tot++;
                dfs(i, 1);
                if(ff) break;
                mxst[++num].mxva=maxx[tot][1], mxst[num].miva=minn[tot][1], mxst[num].opmiva=minn[tot][2], mxst[num].id=tot;
                mxst[++num].mxva=maxx[tot][2], mxst[num].miva=minn[tot][2], mxst[num].opmiva=minn[tot][1], mxst[num].id=tot;
            }
        }
        if(ff){
            puts("IMPOSSIBLE");
            continue;
        }
        sort(mxst+1, mxst+1+num);
        int ans = mxst[1].mxva;
        build(1, tot, 1);
        for(int i=1; i<=num; i++){
            vis[mxst[i].id] ++;
            update(1, tot, 1, mxst[i].id, mxst[i].opmiva);
            ans = min(ans, mxst[i].mxva-T[1].mi);
            if(vis[mxst[i].id]==2) break;
            update(1, tot, 1, mxst[i].id, mxst[i].miva);
        }
        printf("%d\n",ans);
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值