测试1T3

[提交][状态][讨论版]

题目描述

小天才lyk喜欢玩一个叫pinball的游戏。游戏规则如下:
Pinball的游戏界面由m+2行、n列组成。第一行在顶端。一个球会从第一行出发,开始垂直下落,lyk会得到一个积分当他击中一个球的时候。
小天才lyk觉得这太困难了,于是在界面中放入了一些漏斗,一共有m个漏斗分别放在第2~m+1行,第i个漏斗的作用是把经过第i+1行且列数在Ai~Bi之间的球将其移到第Ci列。
但是使用每个漏斗都是需要付钱的,第i个漏斗需要支付Di的价钱,lyk需要保留一些漏斗,使得球无论从第一行的哪一列开始放,都只可能到达第m+2行的唯一一列。同时,lyk希望花费最小的价钱。

输入

第一行两个数,m和n
接下来m行,第i+1行描述第i个漏斗的属性,Ai,Bi,Ci,Di(1<=Ai<=Ci<=Bi<=n,1<=Di<=1000000000)。

输出

若不存在一种方案能满足条件则输出-1,否则输出最小话费。

样例输入

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



3 5
2 4 3 10
1 3 1 20
2 5 4 30

样例输出

25


-1

提示

【样例解释1】



如图,只需使用第2、4、5个漏斗即可。


【数据范围】

对于20%的数据,m<=10,n<=1000

对于 40%的数据,m<=200

对于60%的数据,m<=1000

对于100%的数据,m<=100000,2<=n<=1000000000

 
原题等价于第一列和第n列最终掉在同一列上
l[i]表示从第1列到第i列最后使用漏斗i到达c[i]的最小花费
l[i]=min(l[j]:a[i]<=c[j]<=b[i]+d[i]);
这是个离散化的rmq问题
用线段树就行
离散化~~
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
using namespace std;
#define ll long long
const ll INF=(ll)1<<60;
#define N 110000
int n,m,a[N],b[N],c[N],d[N],q[N];
ll ans=INF;
struct seg{
    ll Min[N*4],a[N];
    void build(int u,int l,int r){
        if(l==r){
            Min[u]=a[l];
            return;
        }
        int mid=(l+r)>>1;
        build(u*2,l,mid);
        build(u*2+1,mid+1,r);
        Min[u]=min(Min[u*2],Min[u*2+1]);
    }
    ll find(int u,int l,int r,int x,int y){
        if(x<=l && y>=r)return Min[u];
        if(x>r || y<l)return INF;
        int mid=(l+r)>>1;
        return min(find(u*2,l,mid,x,y),find(u*2+1,mid+1,r,x,y));
    }
    void change(int u,int l,int r,int x,ll w){
        if(l==r){
            Min[u]=min(w,Min[u]);
            return;
        }
        int mid=(l+r)>>1;
        if(x<=mid)change(u*2,l,mid,x,w);
        else change(u*2+1,mid+1,r,x,w);
        Min[u]=min(Min[u*2],Min[u*2+1]);
    }
}t1,t2;
int bin1(int k){
    int l=1,r=q[0];
    while(l<r){
        int mid=(l+r)/2;
        if(q[mid]>=k)r=mid;
        else l=mid+1;
    }
    return l;
}
int bin2(int k){
    int l=1,r=q[0];
    while(l<r){
        int mid=(l+r)/2+1;
        if(k>=q[mid])l=mid;
        else r=mid-1;
    }
    return l;
}
int main(){
    freopen("pinball.in","r",stdin);
    freopen("pinball.out","w",stdout);
    scanf("%d%d",&n,&m);
    q[++q[0]]=1;
    q[++q[0]]=m;
    for(int i=1;i<=n;i++)scanf("%d %d %d %d",&a[i],&b[i],&c[i],&d[i]),q[++q[0]]=c[i];
    sort(q+1,q+q[0]+1);
    q[0]=1;
    for(int i=2;i<=n+2;i++)
        if(q[i]!=q[q[0]])q[++q[0]]=q[i];
    m=q[0];
    for(int i=1;i<=q[0];i++){
        t1.a[i]=INF*(int)(i>1);
        t2.a[i]=INF*(int)(i<q[0]);
    }
    t1.build(1,1,q[0]);
    t2.build(1,1,q[0]);
    for(int i=1;i<=n;i++){
        a[i]=bin1(a[i]);
        b[i]=bin2(b[i]);
        c[i]=bin1(c[i]);
        ll f1=t1.find(1,1,q[0],a[i],b[i]),f2=t2.find(1,1,q[0],a[i],b[i]);
        ans=min(f1+f2+d[i],ans);
        t1.change(1,1,q[0],c[i],f1+d[i]);
        t2.change(1,1,q[0],c[i],f2+d[i]);
    }
    if(ans<INF)cout<<ans<<endl;
    else cout<<-1<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/dancer16/p/6840805.html