今天的一场虚拟竞赛
就是一道贪心+模拟
不难,但是wa了好多发。果然还是没有适应这个难度的题目啊

题目让我们求最大可以带走的军队数量。
很显然,我们能够想到二分。
我们从属性值最高的兵开始带走,可以只考虑带的兵中属性值最低的那个人。
所以,我们只需要排个序就行了。
关键是二分中如何二分呢?如何判断,这个属性值可以在规定时间内度过呢?
check()函数是关键!
我们想想哈,假设我的军队走到了1出,发现2处有陷阱,且可以杀死我的军队中最弱的那个人。
那么,身为司令官的我肯定要先去拆除那个陷阱。
假设我需要走到5处才能拆除那个陷阱,那么自然在从2到5这一路,我会把我能拆的陷阱都给拆了。然后我再跑回来带领军队前进

ok,那么我们走到了2,发现3处还有一处有威胁的陷阱,要到才能拆掉他,于是司令我又要跑到6去拆掉这个陷阱。
等等!为什么我们不在刚才跑到5处时再多跑一下,拆掉那个陷阱呢?!
那么,判断司令我还向不向前走的依据是什么呢?
下面给出归纳的结论:
司令我啊,一路向前走拆炸弹,如果我的身后还会有能对我的军队造成威胁的陷阱,那么我就会一直走下去,拆除炸弹。
直到后面没有能再威胁到军队的陷阱,我就回到军队带领军队前进!

ok,这样模拟就行了!!!
但是实际执行起来还是有一定的难度的。

#include<iostream>
#include<algorithm>
#include<functional>
#include<vector>
using namespace std;
typedef long long ll;
const int max_n = 2e5+100;
ll m,n,k,t;
int a[max_n];
vector<int> b[max_n];
vector<int> c[max_n];
bool vis[max_n];
struct trap{
    int l,r,d;
}tr[max_n];
bool check(int mid){
    ll cct = 0;
    if (mid==0)return true;
    int condi = a[mid];
    for (int i=1;i<=k;++i)
        if (tr[i].d<=condi)vis[i]=1;
        else vis[i]=0;
    int i=0,j=0;int to=0;
    for (j=0;j<n;){
        for (int id:b[j+1]){
            if (vis[id])continue;
            else to = max(tr[id].r,to);
        }while (to!=i){
            ++i;
            for (int id:c[i])vis[id]=1;
            for (int id:b[i])if (!vis[id])to=max(to,tr[id].r);
        }
        if (i==j){
            ++cct;++i;++j;++to;
        }
        else{
            cct+=((ll)i-(ll)j)*(ll)3;
            j=i;
        }
    }
    return cct<t;
}

int Solve(){
    int l = 0,r = m;
    int ans = 0;
    while (l<=r){
        int mid = (l+r)>>1;
        if (check(mid)){
            l = mid+1;
            ans = max(ans,mid);
        }
        else r = mid-1;
    }return ans;
}

int main(){
    scanf("%lld %lld %lld %lld",&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",&tr[i].l,&tr[i].r,&tr[i].d);
    for (int i=1;i<=k;++i){
        b[tr[i].l].push_back(i);
        c[tr[i].r].push_back(i);
    }
    sort(a+1,a+1+m,greater<int>());
    printf("%d\n",Solve());
}