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

来源:互联网 发布:保险网络增员话术 编辑:程序博客网 时间:2024/04/30 07:41

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

Data Constraint

Solution

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

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

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

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

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

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

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

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

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

Code

#include<cstdio>#include<algorithm>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(v<key[x])        {            if(!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]<v)        {            if(!s[x][1]) return 0;            x=s[x][1];            continue;        }        if(s[x][0])        {            int y=s[x][0];            while(key[y]<v && s[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;}
1 0
原创粉丝点击