USACO 2007 Dec Gourmet Grazers 挑剔的美食家

挑剔的美食家
约翰的奶牛对食物越来越挑剔了。现在,商店有M 份牧草可供出售,奶
牛食量很大,每份牧草仅能供一头奶牛食用。第i 份牧草的价格为Pi,口感为
Qi。约翰一共有N 头奶牛,他要为每头奶牛订购一份牧草,第i 头奶牛要求
它的牧草价格不低于Ai,口感不低于Bi。请问,约翰应该如何为每头奶牛选
择牧草,才能让他花的钱最少?
输入格式
• 第一行:两个整数N 和M,1 ≤ N ≤ M ≤ 105
• 第二行到第N +1 行:第i+1 行有两个整数Ai 和Bi,1 ≤ Ai;Bi ≤ 109
• 第N + 2 行到第N + M + 1 行:第i + N + 1 行有两个整数Pi 和Qi,
1 ≤ Pi;Qi ≤ 109
输出格式
• 单个整数:表示在满足所有奶牛的要求下的最少总花费,如果不存在这种
方案,输出−1。
样例输入
4 7
1 1
2 3
1 4
4 2
3 2
2 1
4 3
5 2
5 4
2 6
4 4
样例输出
12

第一头牛吃第二份草,花2 元;
第二头牛吃第三份草,花4 元;第三
头牛吃第六份草,花2 元;第四头牛

吃第七份草,花4 元

#include<cstdio>
#include<cstdlib>

const int maxn=100002;
const int maxm=100002;

int n,m,a[maxm],b[maxm],p[maxn],q[maxn];
int lc[maxn],rc[maxn],k[maxn],count[maxn],root,s,height[maxn];
long long ans;

int rightrot(int x);
int leftrot(int x);

int find(int key)
{
	int u=root;
	int c=0;
	while(u!=0)
	{
		if(k[u]<=key)
		{
			c=u;
			u=rc[u];
		}
		else
		{
			u=lc[u];
		}
	}
	return c;
}

int ins(int u,int key)
{
	if(u==0)
	{
		u=++s;
		k[u]=key;
		height[u]=rand();
	}
	else if(k[u]==key)
	{
		count[u]++;
	}
	else if(k[u]<key)
	{
		rc[u]=ins(rc[u],key);
		if(height[u]<height[rc[u]])
		{
			u=leftrot(u);
		}
	}
	else 
	{
		lc[u]=ins(lc[u],key);
		if(height[u]<height[lc[u]])
		{
			u=rightrot(u);
		}
	}
	return u;
}

int leftrot(int x)
{
	int y=rc[x];
	rc[x]=lc[y];
	lc[y]=x;
	return y;
}

int rightrot(int x)
{
	int y=lc[x];
	lc[x]=rc[y];
	rc[y]=x;
	return y;
}

int pop(int u)
{
	if(rc[u]==0)
		return lc[u];
	if(lc[u]==0)
		return rc[u];
	if(height[rc[u]]<height[lc[u]])
	{
		int x=rightrot(u);
		rc[x]=pop(u);
		return x;
	}
	else
	{
		int x=leftrot(u);
		lc[x]=pop(u);
		return x;
	}
}

int del(int u,int key)
{
	if(u!=0)
	{
		if(k[u]<key)
		{
			rc[u]=del(rc[u],key);
		}
		else if(k[u]>key)
		{
			lc[u]=del(lc[u],key);
		}
		else
		{
			if(count[u]!=0)
				count[u]--;
			else
				u=pop(u);
		}
	}
	return u;
}

void swap(int *a,int *b)
{
	int tmp=*a;
	*a=*b;
	*b=tmp;
}

void sort(int l,int r,int a[],int b[])
{
	int key=a[rand()%(r-l+1)+l];
	int i=l,j=r;
	while(i<=j)
	{
		while(a[i]<key)
			i++;
		while(a[j]>key)
			j--;
		if(i<=j)
		{
			swap(&a[i],&a[j]);
			swap(&b[i],&b[j]);
			i++;
			j--;
		}
	}
	if(l<j)
		sort(l,j,a,b);
	if(i<r)
		sort(i,r,a,b);
}

int main()
{
	srand(909978797);
	freopen("gourmet.in","r",stdin);
	freopen("gourmet.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&a[i],&b[i]);
	}
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&p[i],&q[i]);
	}
	sort(1,n,a,b);
	sort(1,m,p,q);
	int hp=1;
	for(int i=1;i<=m;i++)
	{
		while(hp<=n&&a[hp]<=p[i])
		{
			root=ins(root,b[hp]);
			hp++;
		}
		int u=find(q[i]);
		if(u!=0)
		{
			ans+=p[i];
			root=del(root,k[u]);
		}
	}
	printf("%lld\n",ans);
	fclose(stdin);
	fclose(stdout);
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值