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
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;
}