JZOJ 3731. 【NOIP2014模拟7.10】庐州月

Description

【引子】

桥上的恋人入对出双

桥边红药叹夜太漫长

月也摇晃人也彷徨

乌蓬里传来了一曲离殇

庐州月光洒在心上

月下的你不复当年模样

太多的伤难诉衷肠

叹一句当时只道是寻常

庐州月光梨花雨凉

如今的你又在谁的身旁

家乡月光深深烙在我心上

却流不出当年泪光——Vae《庐州月》

【问题描述】

小 G 是出生在庐州的一位同学,当他高中毕业后,回到了自己的家乡。然而家乡已不复当年模样,在高中表现优秀的小G 决定承担起家乡的一件重任,那就是修理已经破烂不堪的石桥。

家乡中共有n 个石桥等待修理,对于第i 个石桥,我们定义两个参数pi,vi,其中pi表示修理石桥的最小花费值,vi表示石桥需要的最小美化需求度。今天,小G 已了解到修理厂共有m 种不同的修理原料,对于第i 种原料,可以对任意

一个石桥的美化度增加di,当然这也需要花费hi的费用。由于发货场的修理原料有限,对于任意一种修理原料,只有一件,也就是说小G 只能选择购买和不购买,对于第i 种修理材料能成功修理第j 个石桥的条件是:当且仅当hi ≥ pj,di ≥vj。现在,已知这n 个石桥修理的最小花费值,最小美化需求度,以及m种修理原料的费用,可对石桥增加的美化度值,请你帮助小G完成这个修理任务。

Input

第一行包括两个正整数,n,m。

接下来 n 行中,每行包括两个正整数pi,vi。

接下来 m行中,每行包括两个正整数hi,di。

Output

只有一个整数,为最小修理花费。如果无法完成修理任务,则输出一个整数

-1。

Sample Input

2 3

2 3

5 9

3 10

3 5

6 11

Sample Output

9

【样例说明】

其中一种可行的方案是:使用第1 种材料,修理第1 个石桥,使用第3 种材

料,修理第2 个石桥,最小修理花费为3 + 6 = 9。

Data Constraint

JZOJ 3731. 【NOIP2014模拟7.10】庐州月_第1张图片

Solution

  • 这是一道典型的贪心题!

  • 把石桥和修理方法都按美化需求度从大到小排序,一个一个石桥修理。

  • 那么维护两个指针,对于一个石桥,就能知道“可能”可以修理的那些方案。

  • 之后,排除掉之前已经选过的那些,其中必有一个最佳方案。

  • 显然, 最佳的一定是花费大于等于当前石桥且其花费最小的!

  • 可是维护这样的集合有一些困难,复杂度一般为 O(NlogN)

  • 这样再加上扫描本身的 O(N) ,是会时间超限的。

  • 于是我们的平衡树算法——Splay,就隆重登场了!

  • 只需基本的插入、删除和求后继操作就可以在 O(logN) 内实现了。

Code

#include
#include
using namespace std;
const int N=100001;
struct data
{
    int x,y;
}a[N],b[N];
int root,tot;
int s[N][2],fa[N],key[N];
long long ans;
inline int read()
{
    int data=0; char ch=0;
    while(ch<'0' || ch>'9') ch=getchar();
    while(ch>='0' && ch<='9') data=data*10+ch-'0',ch=getchar();
    return data;
}
inline bool cmp(data a,data b)
{
    return a.y>b.y;
}
inline bool pd(int x)
{
    return x==s[fa[x]][1];
}
inline void rotate(int x)
{
    int y=fa[x],w=pd(x);
    if(fa[x]=fa[y]) s[fa[y]][pd(y)]=x;
    fa[s[y][w]=s[x][w^1]]=y;
    s[fa[y]=x][w^1]=y;
}
inline void splay(int x)
{
    for(int y;y=fa[x];rotate(x))
        if(fa[y]) rotate(pd(x)==pd(y)?y:x);
    root=x;
}
inline int search(int x,int v)
{
    while(key[x]!=v)
        if(vif(!s[x][0]) break;
            x=s[x][0];
        }else
        {
            if(!s[x][1]) break;
            x=s[x][1];
        }
    return x;
}
inline void ins(int &x,int y,int v)
{
    if(!x)
    {
        x=++tot;
        key[x]=v;
        fa[x]=y;
        return;
    }
    ins(s[x][key[x]<=v],x,v);
}
inline void del(int v)
{
    int k=search(root,v);
    splay(k);
    if(!s[k][0])
    {
        fa[root=s[k][1]]=0;
        key[k]=s[k][1]=0;
        return;
    }
    fa[s[k][0]]=0;
    splay(search(s[k][0],1e9));
    if(s[root][1]=s[k][1]) fa[s[root][1]]=root;
    key[k]=s[k][0]=s[k][1]=0;
}
inline int find(int v)
{
    if(!root) return 0;
    int x=root;
    while(true)
    {
        if(key[x]if(!s[x][1]) return 0;
            x=s[x][1];
            continue;
        }
        if(s[x][0])
        {
            int y=s[x][0];
            while(key[y]1]) y=s[y][1];
            if(key[y]>=v)
            {
                x=y;
                continue;
            }
        }
        return x;
    }
}
int main()
{
    int n=read(),m=read();
    for(int i=1;i<=n;i++) a[i].x=read(),a[i].y=read();
    for(int i=1;i<=m;i++) b[i].x=read(),b[i].y=read();
    sort(a+1,a+1+n,cmp);
    sort(b+1,b+1+m,cmp);
    for(int i=1,j=1;i<=n;i++)
    {
        while(j<=m && b[j].y>=a[i].y)
        {
            ins(root,0,b[j++].x);
            splay(tot);
        }
        int k=find(a[i].x);
        if(!k)
        {
            printf("-1");
            return 0;
        }
        ans+=key[k];
        del(key[k]);
    }
    printf("%lld",ans);
    return 0;
}

你可能感兴趣的:(贪心,排序,Splay)