51nod1480 打广告

本文介绍了一道 CodeForces 的算法题,通过将广告和电视频道的时间区间进行匹配来最大化播放的影响系数。采用线段树等数据结构优化搜索过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目来源:  CodeForces
基准时间限制:1 秒 空间限制:131072 KB 分值: 80  难度:5级算法题
 收藏
 关注

有n个广告,从1到n编号,他们要求被播出的时间区间是 [li, ri] (可以只播一部分时间,但是区间一定要在这个里面)。

现在有m个电视频道,从1到m编号,每个频道也相应的播出时间区间 [aj, bj]  ,还有该时间段观看的人数 ci 。

现在就要选一个广告在某个电视台播出,假如播放的时间区间是 [x, y] ,选择的广告资源是i号,电视频道是j号,那么 [x, y] 一定要同时属于  [li, ri] 和 [aj, bj] 。

选好这三个东西后,开始进行播放,那么就会有一个影响系数,是这么计算的  (yx)cj 

现在要进行恰当的选择,使得这个影响系数最大。

样例解释:可以在第1个电视频道中打第2个广告,时间区间定为  [2 4] ,那么影响系数就是  (4  2)2 = 4 。
Input
单组测试数据。
第一行有两个整数n 和 m (1 ≤ n, m ≤ 2*10^5),表示广告数目和电视频道的数目。
接下来n行,每行两个整数 li, ri (0≤ li ≤ ri ≤ 10^9) ,表示每个广告的区间。
接下来m行,每行三个整数 aj, bj, cj (0 ≤ aj ≤ bj ≤ 10^9, 1 ≤ cj ≤ 10^9)。
Output
输出一个最大值,如果不能找到一个有效的方案,输出0。
Input示例
2 3
7 9
1 4
2 8 2
0 4 1
8 9 3
Output示例
4

题解:真的是有点神,由于英文不好,cf上的题解看不太明白。

大致思路就是把广告区间按左端点从小到大,右端点从大到小排序,再把被包含的广告区间删去(因为选这个被包含的肯定不如选包含它的广告好),然后把剩下的广告按位置插入线段树,价值为bi-ai,维护区间最大值。

接下来是判断选哪些广告。

枚举每一个电视频道。首先,被该电视频道完全包含的点就可以从线段树中取出最大值,确定这些点可用二分即可。

对于只包含一部分的,我们显然最优的是选择完全包含的那些点的左边第一个或者右边第一个(因为假设你选左边第二个,此时它的ri小于左边第一个(因为不包含嘛,否则这个点的li小于等于左边第一个,ri大于等于左边第一个,左边第一个点就被包含了,这与我们之前的操作相悖),所以我们不如选左边第一个,此时它的ri更大,与电视频道重叠的一段肯定也更大(因为li是小于电视频道的左端点的嘛,所以ri越大,重叠的也就越多喽)),对于右边第一个点也是同理。

所以在这三者中取最大值即可,该值就是这个电视频道的最大影响系数。

最后对所有电视频道的最大影响系数取个max即可。


代码(copy我校dalao):

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,ma[2000000],d,x,y,z,ans;
struct lsg{int x,y;}a[1000000];
void build(int l,int r,int d){
	if (l==r){ma[d]=a[l].y-a[l].x;return;}
	int m=(l+r)/2;build(l,m,d*2);build(m+1,r,d*2+1);
	ma[d]=max(ma[d*2],ma[d*2+1]);
}int findit(int x,int y,int l,int r,int d){
	if (x<=l&&y>=r)return ma[d];int m=(l+r)/2,ans=0;
	if (x<=m)ans=max(ans,findit(x,y,l,m,d*2));
	if (y>m)ans=max(ans,findit(x,y,m+1,r,d*2+1));
	return ans;
}int doit(int x,int y){
	if (x>a[d].y||y<a[1].x)return 0;
	int l=1,r=d,xx,yy,dd=0;
	while (l<r){
		int m=(l+r)/2;if (a[m].x>x)r=m;else l=m+1;
	}
	if (x>a[d].x)xx=d+1;else xx=l;
	l=1;r=d;
	while (l<r){
		int m=(l+r+1)/2;if (a[m].y<y)l=m;else r=m-1;
	}
	if (y<a[1].y)yy=0;else yy=l;
	if (xx<=yy)dd=findit(xx,yy,1,d,1);
	if (xx-1>0)dd=max(dd,min(y,a[xx-1].y)-max(x,a[xx-1].x));
	if (yy+1<=d)dd=max(dd,min(y,a[yy+1].y)-max(x,a[yy+1].x));
	return dd;
}bool pd(lsg x,lsg y){return x.x<y.x||x.x==y.x&&x.y>y.y;}
signed main(){
	ios::sync_with_stdio(false);
	cin>>n>>m;for (int i=1;i<=n;i++)cin>>a[i].x>>a[i].y;
	sort(a+1,a+1+n,pd); 
	d=1;for (int i=2;i<=n;i++)if (a[i].y>a[d].y)a[++d]=a[i];
	build(1,d,1);for (int i=1;i<=m;i++){
		cin>>x>>y>>z;ans=max(ans,doit(x,y)*z);
	}cout<<ans<<endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值