【一句话题意】题目大意:有 题目大意:有 N类询问 区间 [l[i],r[i]]各 s[i] 个。有 M类可用区间 [l[i],r[i]]各t[i] 个,现在要对每个询问区间配对上一个包含它的可用区间。
n,m<=4e5
【分析】先按左端点排序n+m个区间(当节点数相同时可用区间在前),如果是可用区间相当于在ri点添加了ti个点。如果是询问区间,则贪心删去在ri点及其右边的si个后继,如果不能删除则输出No,否则是Yes。这样就把关于区间的问题简化为关于点的问题。关于插入、删除、查找后继都可以使用bst做到O(logn)操作。
【分析】
这是一份set的代码,线段树也可做,一位机房大佬硬生生地用分块也卡过了orz。
#pragma GCC optimize(2)
#include<set>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=4e5+1000;
const int inf=1e9;
struct node{
int l,r,s;
int type;
}a[maxn<<1];
int n,m;
inline bool cmp(const node x,const node y){
return x.l==y.l?x.type>y.type:x.l<y.l;
}
inline void read(int &x){
x=0;char tmp=getchar();
while(tmp<'0'||tmp>'9') tmp=getchar();
while(tmp>='0'&&tmp<='9') x=(x<<1)+(x<<3)+tmp-'0',tmp=getchar();
}
void read(int &x,int &y,int &z){read(x),read(y),read(z);}
int main(){
int T;cin>>T;
while(T--){
cin>>n>>m;
for(int i=1;i<=n;i++) read(a[i].l,a[i].r,a[i].s),a[i].type=0;
for(int i=1;i<=m;i++) read(a[i+n].l,a[i+n].r,a[i+n].s),a[i+n].type=1;
n+=m;sort(a+1,a+n+1,cmp);
set<pair<int,int> >s;
s.clear();
bool ok=true;
for(int i=1;i<=n;i++){
if(a[i].type){
s.insert(make_pair(a[i].r,a[i].s));
continue;
} else{
bool flag=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));
flag=true;
break;
}
}
if(!flag){
ok=false;
break;
}
}
}
if(ok) printf("Yes\n");
else printf("No\n");
}
return 0;
}