决赛

题目描述

小 W 准备参加 ION,他认为这是之前所有比赛的决赛,所以要认真准备。他有 N 阶段训 练计划,每一阶段训练计划可以表示为:需要训练编号为 l[i]到 r[i]之间的能力 s[i]天。他还找到了 M 类题目,每一类题目可以表示为:可以训练编号为 l[i]到 r[i]之间的能力,并且这样的一类题目有 k[i]道。 现在小 W 要给每天的训练安排一道题目(同一道题目只能使用一次,每天也只需要使用一道题目),使得题目训练的能力能完全包含需要训练的能力。如果可以达成输出“Yes”, 否则输出“No”。

输入输出格式

输入格式:

 

第一行一个整数 T,表示数据组数。 每组数据第一行两个整数 N,M,分别表示训练的阶段数和题目的种数。 接下来 N 行,每行三个整数 l[i],r[i],s[i],描述一个阶段的训练。 接下来 M 行,每行三个整数 l[i],r[i],k[i],描述一类题目。

 

输出格式:

 

共 T 行,每行一个字符串“Yes”或“No”(不包含引号),表示一组数据的答案。

 

输入输出样例

输入样例#1: 复制

3
2 2
1 4 2
3 5 1
1 4 2
2 5 1
3 2
1 3 1
2 4 1
3 5 1
1 3 2
2 5 1
2 2
1 2 1
1 2 2
1 2 2
1 2 1

输出样例#1: 复制

Yes
No
Yes

说明

【样例解释 1】 对于第一组数据,小 W 有三个阶段的训练计划。 第一个阶段需要训练编号为 1 到 4 的能力 2 天,每天各使用一道训练编号为 1 到 4 能力的 题。 第二个阶段需要训练编号为 3 到 5 的能力 1 天,使用一道训练编号为 2 到 5 能力的题。 【数据范围】 对于 100%的数据,保证 1<=l[i]<=r[i]<=10^9,1<=s[i],k[i]<=10^9,T<=50,1<=N,M<=5 10^4。 记∑N 为一个测试点中所有 N 的和,∑M 为一个测试点中所有 M 的和,有 1<=∑N,∑M<=4 10^5。

 

把 N+M 个区间按照左端点进行排序(左端点相同的情况下可用区间在前)。排序之后扫描
每个区间,如果是可用区间,那么相当于插入了 t[i]个权值为 r[i]的数;如果是询问区间相当
于找到权值大于等于 r[i]的 s[i]个数并删去,发现一定是贪心地删掉权值尽可能小的数。可以
使用线段树维护插入操作,删除的时候先在线段树上二分,然后区间赋值为 0。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 4e5 + 10;
const int inf = 1e9;

struct info
{
	int l , r , s;
	int type;
} a[MAXN << 1];

int n , m;

template <typename T> inline void chkmax(T &x , T y) { x = max(x , y); }
template <typename T> inline void chkmin(T &x , T y) { x = min(x , y); }
template <typename T> inline void read(T &x)
{
   T f = 1; x = 0;
   char c = getchar();
   for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
   for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
   x *= f;
}
inline bool cmp(info a , info b)
{
	return a.l == b.l ? a.type > b.type : a.l < b.l;
} 

int main()
{
	
	#ifndef evenbao
	freopen("c.in" , "r" , stdin);
	freopen("c.out" , "w" , stdout);
	#endif
	
	int T;
	read(T);
	while (T--)
	{
		read(n); read(m);
		for (int i = 1; i <= n; i++)
		{
			read(a[i].l); 
			read(a[i].r);
			read(a[i].s);	
			a[i].type = 1;
		}	
		for (int i = 1; i <= m; i++)
		{
			read(a[n + i].l);
			read(a[n + i].r);
			read(a[n + i].s);
			a[n + i].type = 2;
		}
		sort(a + 1 , a + (n + m) + 1 , cmp);
		set< pair<int , int> > s;
		s.clear();
		bool ok = true;
		for (int i = 1; i <= n + m; i++)
		{
			if (a[i].type == 2) 
			{
				s.insert(make_pair(a[i].r , a[i].s));
				continue;
			} else
			{
				bool flg = false;
				while (!s.empty())
				{
					set< pair<int , int> > :: iterator it = s.lower_bound(make_pair(a[i].r , -inf));
					if (it == s.end()) break;
					pair<int , int> tmp = (*it);
					if (a[i].s > tmp.second)
					{
						s.erase(it);
						a[i].s -= tmp.second;
					} else
					{
						s.erase(it);
						if (tmp.second - a[i].s > 0) s.insert(make_pair(tmp.first , tmp.second - a[i].s));
						flg = true;
						break;
					}
				}
				if (!flg) 
				{
					ok = false;
					break;
				}
			}
		}
		if (ok) printf("Yes\n");
		else printf("No\n");
	}
	
   	return 0;
}
// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define f(i,l,r) for(i=(l);i<=(r);i++)
using namespace std;
const int MAXN=50005;
int n,m,t;
long long ans,L;
struct Event{
    int l,r,s,flag,id;
    bool operator < (const Event& tmp)const{
        if(l==tmp.l){
            return flag<tmp.flag;
        }
        return l<tmp.l;
    }
}a[MAXN<<1];
int h[MAXN<<2];
struct Seg_tree{
    long long  w;
    int lazy;
}T[MAXN<<4];
inline void pushup(int x)
{
    T[x].w=T[x<<1].w+T[x<<1|1].w;
}
inline void pushdown(int x)
{
    T[x<<1].lazy=1;
    T[x<<1|1].lazy=1;
    T[x<<1].w=0;
    T[x<<1|1].w=0;
    T[x].lazy=0;
}
void change(int x,int l,int r,int sj,int tj,int d)
{
    if(sj<=l&&r<=tj){
        if(!d){
            T[x].w=0;
            T[x].lazy=1;
        }
        else{
            T[x].w+=d;
        }
        return;
    }
    if(T[x].lazy) pushdown(x);
    int mid=l+r>>1;
    if(mid>=sj) change(x<<1,l,mid,sj,tj,d);
    if(mid+1<=tj) change(x<<1|1,mid+1,r,sj,tj,d);
    pushup(x);
}
void query(int x,int l,int r,int sj,int tj)
{
    if(sj<=l&&r<=tj){
        ans+=T[x].w;
        return;
    }
    if(T[x].lazy)  pushdown(x);
    int mid=l+r>>1;
    if(mid>=sj) query(x<<1,l,mid,sj,tj);
    if(mid+1<=tj) query(x<<1|1,mid+1,r,sj,tj);
    pushup(x);
}
bool work(int sj,int res)
{
    ans=0;
    query(1,1,L+1,sj,L+1);
    if(ans<res) return 1;
    int l=sj,r=L+1;
    int mid;
    while(l<r){
        mid=(l+r)/2;
        ans=0;
        query(1,1,L+1,sj,mid);
        if(ans>=res){
            r=mid;
        }
        else l=mid+1;
    }
    ans=0;
    query(1,1,L+1,sj,L+1);
    if(ans==res){
        change(1,1,L+1,sj,l,0);
    }
    else{
        if(sj<l){
            ans=0;
            query(1,1,L+1,sj,l-1);
            change(1,1,L+1,sj,l-1,0);
            change(1,1,L+1,l,l,ans-res);
        }
        else{
            change(1,1,L+1,l,l,ans-res);
        }
    }
    return 0;
}
int main()
{
    ios::sync_with_stdio(false);
    int i,j,flag;
    cin>>t;
    while(t--){
        flag=1;
        cin>>n>>m;
        f(i,1,n){
            cin>>a[i].l>>a[i].r>>a[i].s;
            a[i].flag=1;
            a[i].id=i;
            h[i+i-1]=a[i].l;
            h[i+i]=a[i].r;
        }
        f(i,n+1,n+m){
            cin>>a[i].l>>a[i].r>>a[i].s;
            a[i].flag=0;
            a[i].id=i;
            h[i+i-1]=a[i].l;
            h[i+i]=a[i].r;
        }
        sort(h+1,h+1+(n+m)*2);
        L=unique(h+1,h+1+(n+m)*2)-(h+1);
        sort(a+1,a+1+n+m);
        change(1,1,L+1,1,L+1,0);
        f(i,1,n+m){
            int pos=lower_bound(h+1,h+1+L,a[i].r)-h;
            if(!a[i].flag){
                 change(1,1,L+1,pos,pos,a[i].s);
            }
            else{
                if(work(pos,a[i].s)){
                    cout<<"No"<<endl;
                    flag=0;
         			break;
                }
            }
        }
        if(flag) cout<<"Yes"<<endl;
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值