【L,R的特点】codeforce 822C Hacker, pack your bags!

codeforce 822C     Hacker, pack your bags!

给出x,几个区间(l,r)以及其值,选择两个不相交的区间,要求其和为x,并cost最小。

难点: n(区间个数)<= 2*10^5,要求两个区间不相交。
解决方法:  均是根据L,R特点:

1.根据其中一个排序,如果对L排序,那么在i区间前面的区间的L一定是满足小于当前L,那么前面的区间如果R满足小于当前L,那么他对

当前区间以下的区间全部不相交。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
//#pragma comment(linker, "/STACK:102400000,102400000")

const double PI = acos(-1.0);
const double eps = 1e-6;
//const int INF=0x3f3f3f3f;
const LL INF = 1e18;
const LL mod = 1e9+7;
const int N=2*100005;
const int M = 2500000;

struct node{
    int l,r;
    int day;
    int cost;
    bool operator <(const node &a) const{
        return r>a.r;
    }
}a[N];
bool cmp(node a,node b){
    return a.l < b.l;
}
map<int,int> mp;
int main(){
    int n,x;
    scanf("%d%d",&n,&x);
    for(int i = 0; i < n; i++){
        scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].cost);
        a[i].day = a[i].r-a[i].l+1;
    }
    sort(a,a+n,cmp);
    priority_queue<node> Q;
    mp.clear();
    LL mi = INF;
    for(int i = 0; i < n; i++){
        while(!Q.empty()){
            node tmp = Q.top();
            if(tmp.r < a[i].l){
                Q.pop();
                int f = tmp.day;
                if(mp.find(f) == mp.end())
                    mp[f] = tmp.cost;
                else
                    mp[f] = min(mp[f],tmp.cost);
            }
            else
                break;
        }
        Q.push(a[i]);
        if(mp.find(x-a[i].day) == mp.end())
            continue;
        else
            mi = min(mi,(LL)mp[x-a[i].day]+(LL)a[i].cost);
    }
    if(mi == INF)
        puts("-1");
    else
        printf("%I64d\n",mi);
    return 0;
}



2. 将区间的L,R直接记录下来,从0到最远距离循环过来,同样根据当前位置如果是R,那么以后的L全于其不相交。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
//#pragma comment(linker, "/STACK:102400000,102400000")

const double PI = acos(-1.0);
const double eps = 1e-6;
//const int INF=0x3f3f3f3f;
const LL INF = 1e18;
const LL mod = 1e9+7;
const int N = 2*1e5+10;
const int M = 2500000;

vector<pair<int,int> > l[N],r[N];
LL mp[N];
int main(){
    int n,x;
    scanf("%d%d",&n,&x);
    for(int i = 0; i < n; i++){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        l[a].push_back(make_pair((b-a+1),c));
        r[b].push_back(make_pair((b-a+1),c));
    }
    LL mi = INF;
    for(int i = 0; i < N; i++)
        mp[i] = INF;
    for(int i = 1; i < N; i++){
        for(int j = 0; j < l[i].size(); j++){
            if(x-l[i][j].first <= 0)
                continue;
            if(mp[x-l[i][j].first] != INF)
                mi = min(mi,mp[x-l[i][j].first]+(LL)l[i][j].second);
        }
        for(int j = 0; j < r[i].size(); j++){
            mp[r[i][j].first] = min(mp[r[i][j].first],(LL)r[i][j].second);
        }
    }
    if(mi == INF){
        puts("-1");
    }
    else
        printf("%I64d\n",mi);
    return 0;
}



3.根据二分的思想,明显先要按照r-l+1排序,但处理出来是还是一个范围,那么还得将R作为第二关键词排序。因为这样对于一个L,比一个区间的R小,那么这个区间和前面的区间都不相交,那么如果预处理 相同(r-l+1)中前缀最小值,那么就能强行二分计算一波了。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
//#pragma comment(linker, "/STACK:102400000,102400000")

const double PI = acos(-1.0);
const double eps = 1e-6;
//const int INF=0x3f3f3f3f;
const LL INF = 1e18;
const LL mod = 1e9+7;
const int N=2*100005;
const int M = 2500000;

struct node{
    int l,r;
    int day;
    int cost;
    int micost;
}a[N];
bool cmp(node a,node b){
    if(a.day != b.day)
        return a.day < b.day;
    return a.r < b.r;
}
LL Binseach(int l,int r,int eday,int el){
    LL ans = INF;
    int mid;
    while(l <= r){
        mid = l+(r-l>>1);
        if(a[mid].day < eday)
            l = mid+1;
        else if(a[mid].day == eday){
            if(a[mid].r < el){
                l = mid+1;
                ans = min(ans,(LL)a[mid].micost);
            }
            else
                r = mid-1;
        }
        else
            r = mid-1;
    }
    return ans;
}
int main(){
    int n,x;
    scanf("%d%d",&n,&x);
    for(int i = 0; i < n; i++){
        scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].cost);
        a[i].day = a[i].r-a[i].l+1;
        a[i].micost = a[i].cost;
    }
    sort(a,a+n,cmp);
    for(int i = 1; i < n; i++){
        if(a[i].day == a[i-1].day)
            a[i].micost = min(a[i].micost,a[i-1].micost);
    }
    LL mi = INF;
    for(int i = 0; i < n; i++){
        LL ans = Binseach(0,n-1,x-a[i].day,a[i].l);
        //printf("%d %d\n",i,ans);
        mi = min(mi,(LL)ans+(LL)a[i].cost);
    }
    if(mi == INF)
        puts("-1");
    else
        printf("%I64d\n",mi);
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值