Educational Codeforces Round 77 D.A Game with Traps(二分+差分+前缀和)

题目描述

You are playing a computer game, where you lead a party of m soldiers. Each soldier is characterised by his agility ai.
The level you are trying to get through can be represented as a straight line segment from point 0 (where you and your squad is initially located) to point n+1 (where the boss is located).
The level is filled with k traps. Each trap is represented by three numbers li, ri and di. li is the location of the trap, and di is the danger level of the trap: whenever a soldier with agility lower than di steps on a trap (that is, moves to the point li), he gets instantly killed. Fortunately, you can disarm traps: if you move to the point ri, you disarm this trap, and it no longer poses any danger to your soldiers. Traps don’t affect you, only your soldiers.
You have t seconds to complete the level — that is, to bring some soldiers from your squad to the boss. Before the level starts, you choose which soldiers will be coming with you, and which soldiers won’t be. After that, you have to bring all of the chosen soldiers to the boss. To do so, you may perform the following actions:
if your location is x, you may move to x+1 or x−1. This action consumes one second;
if your location is x and the location of your squad is x, you may move to x+1 or to x−1 with your squad in one second. You may not perform this action if it puts some soldier in danger (i. e. the point your squad is moving into contains a non-disarmed trap with di greater than agility of some soldier from the squad). This action consumes one second;
if your location is x and there is a trap i with ri=x, you may disarm this trap. This action is done instantly (it consumes no time).
Note that after each action both your coordinate and the coordinate of your squad should be integers.
You have to choose the maximum number of soldiers such that they all can be brought from the point 0 to the point n+1 (where the boss waits) in no more than t seconds.

Input

The first line contains four integers m, n, k and t (1≤m,n,k,t≤2⋅105, n<t) — the number of soldiers, the number of integer points between the squad and the boss, the number of traps and the maximum number of seconds you may spend to bring the squad to the boss, respectively.
The second line contains m integers a1, a2, …, am (1≤ai≤2⋅105), where ai is the agility of the i-th soldier.
Then k lines follow, containing the descriptions of traps. Each line contains three numbers li, ri and di (1≤li≤ri≤n, 1≤di≤2⋅105) — the location of the trap, the location where the trap can be disarmed, and its danger level, respectively.

Output

Print one integer — the maximum number of soldiers you may choose so that you may bring them all to the boss in no more than t seconds.

Example

input
5 6 4 14
1 2 3 4 5
1 5 2
1 2 5
2 3 5
3 5 3
output
3

Note

In the first example you may take soldiers with agility 3, 4 and 5 with you. The course of action is as follows:
go to 2 without your squad;
disarm the trap 2;
go to 3 without your squad;
disartm the trap 3;
go to 0 without your squad;
go to 7 with your squad.
The whole plan can be executed in 13 seconds.

题目大意

你在玩一个游戏,你有m个士兵,每个士兵的敏捷度是a[i]。你要从位置0出发,到位置n+1去打boss。
这一路上有k个陷阱,每个陷阱都有l[i],r[i],d[i]三个属性。当士兵位于l[i]的位置时,就会触发陷阱,如果士兵的敏捷度a[i]小于d[i],那么这个士兵会被杀掉。不过当你位于r[i]的位置时,你可以排除该陷阱(你不会触发陷阱)。
你有t秒的时间去进行移动,你有两种移动方式:1.如果你位于x位置,那么你可以移动到x+1或者x-1的位置上。2.如果你和你的部队都在x位置上,你可以带着你的部队移动到x+1或者x-1的位置上(你也可以不带部队行动)。两种行动都只花费一秒。
问你最多可以从m个士兵中带多个人去打boss,使得移动时间不超过t秒,且在路上没有伤亡。

题目分析

这道题的数据范围比较大,而且带多少人去这个问题存在单调性,带的人越多,就需要花越多的时间去排雷,而题目中要求的时间最大值是固定的。因此这道题可以用二分来解决。
这道题可以之间二分答案(应该带多少人去),因此一开始 l=0,r=m。然后检查mid是否合法:
算出如果带mid个人去要花多长时间,这个这个时间设为sum。
如果sum<=t,则mid为合法解,那么可以进一步计算看看该解是否可以更大一些(即:l=mid,mid为合法解,所以要保留)。
如果sum>t,则mid不合法(过大),因此要减小mid(即:r=mid-1,mid为非法解,不需要保留)。
最后留下的 l 即为答案。

补充:求sum的具体方法
为了让mid个人顺利通过,应该先找出需要排哪些陷阱,先找出mid个人中灵敏度的最小值,要排的陷阱即为所有d大于该最小值的陷阱。我们排陷阱的起点为要排的所有陷阱l的最小值,终点为r的最大值,这就是排陷阱的路程区间。
这个路程区间可以通过差分和前缀和来找,找出所有要排的陷阱的[l,r]区间,用差分给[l,r]的区间都加上1,再用前缀和来还原数组。这样就得到了排陷阱的路程区间。

代码如下
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <map>
#include <queue>
#include <vector>
#include <set>
#include <algorithm>
#include <iomanip>
#define LL long long
using namespace std;
const int N=2e5+5;
struct Node{
	int l,r,d;
}s[N];
int n,m,k,t;
int a[N],cnt[N];	//cnt[]即为排雷的路程区间
bool check(int mid)
{
	memset(cnt,0,sizeof cnt);
	for(int i=1;i<=k;i++)	//利用差分,给[l,r]都加1
	if(a[mid]<s[i].d)
	{
		cnt[s[i].l]++,cnt[s[i].r+1]--;
	}
	for(int i=1;i<=n+1;i++)		//前缀和还原
		cnt[i]+=cnt[i-1];
	
	int sum=0;
	for(int i=1;i<=n+1;i++)		//记录区间长度
		if(cnt[i]) sum++;
	
	return 2*sum+n+1<=t;
}
int main()
{
	scanf("%d %d %d %d",&m,&n,&k,&t);
	for(int i=1;i<=m;i++)
		scanf("%d",&a[i]);
	
	for(int i=1;i<=k;i++)
		scanf("%d %d %d",&s[i].l,&s[i].r,&s[i].d);
	
	sort(a+1,a+1+m,greater<int>());	//按从大到小进行排序
	int l=0,r=m;
	while(r>l)	//二分过程
	{
		int mid=l+r+1>>1;
		if(check(mid)) l=mid;
		else r=mid-1;
	}
	cout<<l<<endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lwz_159

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值