2018 ccpcfinal Gym - 102055B滑动窗口

这篇博客探讨了一种解决限制条件下求最大最小差值问题的算法。通过将人转化为联通块,并对四种属性值进行排序,实现了在考虑约束条件下的滑动窗口求解。文章详细介绍了如何处理不同联通块的选择,以及如何在存在不能同时选择A或B的情况下来找到最小的差值。算法涉及图的遍历、颜色编码和滑动窗口等概念,对于优化问题的解决提供了新的思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意问你 给你 n个人 每个人 有两种属性 可以选择 A 选择 B 但是有些人 不能同时选 A或者 同时选B 问最后得到的 MAX - MIN 最小

首先没有 人限制的话 那么就是个经典题 滑动窗口求 差值最小 只需要把两个值拆分 sort一下 然后每次找到 n 个人 的属性取一下 min 即可
有限制的话 无非是 把人变成了联通块 多个联通块 组合求差值 此题 是 每个人选择两种值 每个联通块就有两种 maxn 和 minn 我们只需要拆分成 4种值进行排序即可

#include<iostream>
#include<algorithm>
#include<cstring>
#define x first
#define y second

using namespace std;

const int N = 2e5 + 10,M = N * 2;
typedef pair<pair<int,int> ,pair<int,int> > PII;

struct node{
    int x,id,type;
    bool operator < (const node &p)const{
        return x < p.x;
    }
}c[M * 2];

int a[N],b[N];
int head[N],to[M],last[M],cnt;
void add(int a,int b){
    to[++cnt] = b;
    last[cnt] = head[a];
    head[a] = cnt;
}

bool flag;
int color[N];
PII get_color(int x,int pre){
    int maxn1 = a[x],minn1 = a[x];
    int maxn2 = b[x],minn2 = b[x];
    for(int i = head[x]; i != -1; i = last[i]){
        int j = to[i];
        if(pre == j) continue;
        if(color[j] == 3) color[j] = color[x] ^ 1;
        else{
            if(color[j] != (color[x] ^ 1)){
                flag = false;
                return {{0,0},{0,0}};
            }else continue;
        }
        PII p = get_color(j,x);
        maxn1 = max(maxn1,p.y.x);
        minn1 = min(minn1,p.y.y);
        maxn2 = max(maxn2,p.x.x);
        minn2 = min(minn2,p.x.y);
    }
    return {{maxn1,minn1},{maxn2,minn2}};
}
PII ve[N];

int st[N][3];

int main(){
    int t;
    cin >> t;
    int CASE = 0;
    while(t--){
        int n,m;
        cin >> n >> m;
        memset(st,0,sizeof st);
        memset(head,-1,sizeof head);
        flag = true;
        cnt = 0;
        for(int i = 1; i <= m; i++){
            int x,y;
            scanf("%d%d",&x,&y);
            add(x,y);
            add(y,x);
        }

        for(int i = 1; i <= n; i++){
            scanf("%d%d",&a[i],&b[i]);
        }
        for(int i = 1; i <= n; i++) color[i] = 3;

        int ans = 0;
        for(int i = 1; i <= n; i++){
            if(color[i] == 3){
                color[i] = 1;
                ve[++ans] = get_color(i,0);
            }else continue;
        }

        printf("Case %d: ",++CASE);
        if(!flag){
            printf("IMPOSSIBLE\n");
            continue;
        }

        int d = 0;
        for(int i = 1; i <= ans; i++){
            c[++d] = {ve[i].x.x,i,0};
            //cout << ve[i].x.x << " " << ve[i].x.y << " " << ve[i].y.x<< " " << ve[i].y.y << "asd" <<endl;
            c[++d] = {ve[i].x.y,i,0};
            c[++d] = {ve[i].y.x,i,1};
            c[++d] = {ve[i].y.y,i,1};
        }

        sort(c + 1,c + d + 1);

        int minn = 0x3f3f3f3f;
        int r = 1,s = 0;
        for(int i = 1; i <= d; i++){
            st[c[i - 1].id][c[i - 1].type]--;
            if(st[c[i - 1].id][c[i - 1].type] == 1 && st[c[i - 1].id][c[i - 1].type ^ 1] != 2) s--;
            while(r <= d && s < ans){
                st[c[r].id][c[r].type]++;
                if(st[c[r].id][c[r].type] == 2 && st[c[r].id][c[r].type ^ 1] != 2) s++;
                r++;
            }
            if(c[i].id == c[r - 1].id && c[i].type != c[r - 1].type) continue;
            if(s != ans) continue;
            minn = min(minn,c[r - 1].x - c[i].x);
        }

        cout << minn << endl;

    }





    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值