It looks very greedy, sort according to the right endpoint, use the minimum line segment tree query to determine whether the current cow can be put in, and update the line segment tree if it can. Ans++
comes from https://www.cnblogs.com/rausen/p/ 4529245.htmlVery rigorous proof
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=100005;
int n,m,c[N],ans;
struct xds
{
int l,r,mn,lz;
}t[N<<2];
struct qwe
{
int l,r;
}a[N];
bool cmp(const qwe &a,const qwe &b)
{
return a.r<b.r;
}
int read()
{
int r=0,f=1;
char p=getchar();
while(p>'9'||p<'0')
{
if(p=='-')
f=-1;
p=getchar();
}
while(p>='0'&&p<='9')
{
r=r*10+p-48;
p=getchar();
}
return r*f;
}
void pd(int ro)
{
if(t[ro].lz!=0)
{
t[ro<<1].mn-=t[ro].lz,t[ro<<1].lz+=t[ro].lz;
t[ro<<1|1].mn-=t[ro].lz,t[ro<<1|1].lz+=t[ro].lz;
t[ro].lz=0;
}
}
void build(int ro,int l,int r)
{
t[ro].l=l,t[ro].r=r;
if(l==r)
{
t[ro].mn=c[l];
return;
}
int mid=(l+r)>>1;
build(ro<<1,l,mid);
build(ro<<1|1,mid+1,r);
t[ro].mn=min(t[ro<<1].mn,t[ro<<1|1].mn);
}
void update(int ro,int l,int r)
{
if(t[ro].l==l&&t[ro].r==r)
{
t[ro].mn--,t[ro].lz++;
return;
}
pd(ro);
int mid=(t[ro].l+t[ro].r)>>1;
if(r<=mid)
update(ro<<1,l,r);
else if(l>mid)
update(ro<<1|1,l,r);
else
update(ro<<1,l,mid),update(ro<<1|1,mid+1,r);
t[ro].mn=min(t[ro<<1].mn,t[ro<<1|1].mn);
}
int ques(int ro,int l,int r)
{
if(t[ro].l==l&&t[ro].r==r)
return t[ro].mn;
pd(ro);
int mid=(t[ro].l+t[ro].r)>>1;
if(r<=mid)
return ques(ro<<1,l,r);
else if(l>mid)
return ques(ro<<1|1,l,r);
else
return min(ques(ro<<1,l,mid),ques(ro<<1|1,mid+1,r));
}
int main()
{
n=read(),m=read();
for(int i=1;i<=n;i++)
c[i]=read();
for(int i=1;i<=m;i++)
a[i].l=read(),a[i].r=read();
sort(a+1,a+1+m,cmp);
build(1,1,n);
for(int i=1;i<=m;i++)
if(ques(1,a[i].l,a[i].r)>0)
update(1,a[i].l,a[i].r),ans++;
printf("%d\n",ans);
return 0;
}