题目链接:http://poj.org/problem?id=3622
题目大意:给出n头牛,每头牛有两个属性:金钱,美味。m个产品,每个产品有两个属性:金钱,美味。只有一个产品的两个属性都大于等于牛的时候,这头牛才会去吃这个产品。问使n头牛都能吃上产品,最少花费多少。如果不能满足,输出-1;
思路:将牛的属性按照美味从大到小排列,将产品的美味从小到大排列。然后依次选牛。对于每头牛,二分出第一个可选的美味。将可选的美味都放入SplayTree中。然后从中找出最少花费的一个产品。移除SplayTree。总体复杂度O(n*log(m)*log(m))。
900+ms险过(SplayTree常数有点大)。
ACCode:
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<stdlib.h>
#include<time.h>
// srand(unsigned)time(NULL));rand();
#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
#define ll long long
#define Pair pair<int,int>
#define clean(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN=1e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll MOD=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
//unsigned register
// ios::sync_with_stdio(false)
class SplayTree{
struct Node{
ll A,B;
int l,r,f,siz;
Node(ll _A=0,ll _B=0,int _l=0,int _r=0,int _f=0,int _siz=0){
A=_A;B=_B;l=_l;r=_r;f=_f;siz=_siz;
}
friend int operator < (Node a,Node b){
if(a.A==b.A) return a.B<b.B;
return a.A<b.A;
}
};
Node Tree[MAXN];
int Lazy[MAXN];
int Rt,Ecnt;//Rt的父节点是0,第一个节点从1开始。
void PushUp(int x){//次序
Tree[x].siz=Tree[Tree[x].l].siz+Tree[Tree[x].r].siz+1;
}
void PushDown(int x){//反转
if(Lazy[x]){
int temp=Tree[x].l;Tree[x].l=Tree[x].r;Tree[x].r=temp;
Lazy[Tree[x].l]^=1;Lazy[Tree[x].r]^=1;
Lazy[x]=0;
}
}
void Rotate(int x,int oper){
int y=Tree[x].f;
PushDown(y);PushDown(x);
if(oper){
Tree[y].r=Tree[x].l;
if(Tree[x].l!=0) Tree[Tree[x].l].f=y;
Tree[x].l=y;
}
else{
Tree[y].l=Tree[x].r;
if(Tree[x].r!=0) Tree[Tree[x].r].f=y;
Tree[x].r=y;
}Tree[x].f=Tree[y].f;
if(Tree[y].f){
if(y==Tree[Tree[y].f].l) Tree[Tree[y].f].l=x;
else Tree[Tree[y].f].r=x;
}Tree[y].f=x;PushUp(y);
}
void Splay(int x,int f){
PushDown(x);
int y=Tree[x].f,z=0;
while(y!=f){
z=Tree[y].f;
PushDown(z);PushDown(y);PushDown(x);
if(z==f) Rotate(x,x==Tree[y].r);
else{
if((x==Tree[y].l^y==Tree[z].l)==0){
Rotate(y,y==Tree[z].r);Rotate(x,x==Tree[y].r);
}
else{
Rotate(x,x==Tree[y].r);Rotate(x,x==Tree[z].r);
}
}PushUp(x);y=Tree[x].f;
}PushUp(x);
if(f==0) Rt=x;
}
int MinNode(ll Key){
int x=Rt,ans=-1;
PushDown(x);
while(1){
if(Tree[x].A>=Key){//该节点可以取得
ans=x;
if(Tree[x].l) x=Tree[x].l;//向左子节点
else return ans;
}
else{//不可以取得
if(Tree[x].r) x=Tree[x].r;//可以的话直接向右走了
else return ans;//没有符合要求的
}
}
}
int GetPre(){
int x=Rt;
if(Tree[x].l) x=Tree[x].l;
else return x;
while(1){
if(Tree[x].r) x=Tree[x].r;
else return x;
}
}
public:
void Intt(){
clean(Lazy,0);
Rt=0;Ecnt=0;
}
void Insert(ll A,ll B){
Tree[++Ecnt]=Node(A,B,0,0,0,1);
int y=0,x=Rt;
while(x){
y=x;
if(Tree[Ecnt]<Tree[x]) x=Tree[x].l;
else if(Tree[x]<Tree[Ecnt]) x=Tree[x].r;
else return ;
}
if(y==0) Rt=Ecnt;
else if(Tree[Ecnt]<Tree[y]){
Tree[y].l=Ecnt;Tree[Ecnt].f=y;
}
else{
Tree[y].r=Ecnt;Tree[Ecnt].f=y;
}Splay(Ecnt,0);
}
ll DeleteMin(ll Key){//所有的B都符合要求,找到最小的A>=P
int Pos=MinNode(Key);
if(Pos==-1) return -1;
ll Ans=Tree[Pos].A;
Splay(Pos,0);
//cout<<"Pos,Pre:"<<Pos<<" "<<GetPre()<<endl;
Splay(GetPre(),0);//cout<<"Debug:\n";Show(Rt);cout<<"End\n";
if(Pos==GetPre()){
Rt=Tree[Rt].r;Tree[Rt].f=0;
}
else{
Splay(Pos,Rt);
Tree[Rt].r=Tree[Pos].r;Tree[Tree[Rt].r].f=Rt;
}
return Ans;
}
//-------
int GetRt(){
return Rt;
}
void Show(int x){
if(x==0) return ;
PushDown(x);
printf("x:%d xf:%d xl:%d xr:%d (A,B)(%lld,%lld)\n",x,Tree[x].f,Tree[x].l,Tree[x].r,Tree[x].A,Tree[x].B);
Show(Tree[x].l);
// printf("A:%lld B:%lld\n",Tree[x].A,Tree[x].B);
Show(Tree[x].r);
}
};
struct Node{
ll P,G;
Node(ll _P=0,ll _G=0){
P=_P;G=_G;
}
friend int operator < (Node a,Node b){
if(a.G==b.G) return a.P<b.P;
return a.G<b.G;
}
};
SplayTree Spl;
Node Cows[MAXN],Goods[MAXN];
int n,m;
int PosX(ll Key,int l,int r){
while(l<=r){
int mid=(l+r)>>1;
if(Goods[mid].G<Key) l=mid+1;
else r=mid-1;
}return l;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) scanf("%lld%lld",&Cows[i].P,&Cows[i].G);
for(int i=1;i<=m;++i) scanf("%lld%lld",&Goods[i].P,&Goods[i].G);
sort(Cows+1,Cows+1+n);sort(Goods+1,Goods+1+m);
ll ans=0;int flag=1,tmp=m;
Spl.Intt();
for(int i=n;i>=1;--i){
int Pos=PosX(Cows[i].G,1,tmp);
for(int j=Pos;j<=tmp;++j) Spl.Insert(Goods[j].P,Goods[j].G);
ll temp=Spl.DeleteMin(Cows[i].P);
if(temp==-1){//找最小的花费
flag=0;break;
}ans+=temp;tmp=Pos-1;
}
if(flag==0) printf("-1\n");
else printf("%lld\n",ans);
}