solution:
我们将所有区间按照左端点排序后,从右往左,能添加则添加不能就不添加,这样贪心是正确的。因为我们可以维护两个性质:
1.最大性
2.方案对后面的区间一定是最优的。证明略。
能这么做的原因是因为这道题是无权的。
假如区间有权的话,那么等价于选出K条路径,路径上每个区间不相交且权值最大,可以用费用流做。
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int M=100010;
int n,m,res,x,y;
int t[M<<2],s[M<<2];
struct Node
{
int u,v;
friend bool operator <
(const Node a,const Node b)
{
if(a.u==b.u)return a.v<b.v;
else return a.u<b.u;
}
}a[M];
void build(int o,int l,int r)
{
if(l==r)
{
scanf("%d",&t[o]);
return;
}
int M=l+r>>1;
build(o<<1,l,M);
build(o<<1|1,M+1,r);
t[o]=min(t[o<<1],t[o<<1|1]);
}
inline void pushdown(int o)
{
if(s[o])
{
int l=o<<1;
int r=l+1;
s[l]+=s[o];
s[r]+=s[o];
t[l]-=s[o];
t[r]-=s[o];
s[o]=0;
}
}
int ask(int o,int l,int r)
{
if(x<=l && y>=r)return t[o];
pushdown(o);
int M=l+r>>1,ans=M;
if(x<=M)ans=min(ans,ask(o<<1,l,M));
if(y>M)ans=min(ans,ask(o<<1|1,M+1,r));
return ans;
}
void update(int o,int l,int r)
{
if(x<=l && y>=r)
{
t[o]--;
s[o]++;
return;
}
pushdown(o);
int M=l+r>>1;
if(x<=M)update(o<<1,l,M);
if(y>M)update(o<<1|1,M+1,r);
t[o]=min(t[o<<1],t[o<<1|1]);
}
int main()
{
scanf("%d %d",&n,&m);
build(1,1,n);
for(int i=1;i<=m;++i)
scanf("%d %d",&a[i].u,&a[i].v);
sort(a+1,a+1+m);
for(int i=m;i>=1;--i)
{
x=a[i].u;
y=a[i].v;
if(ask(1,1,n)<1)continue;
res++;
update(1,1,n);
}
printf("%d\n",res);
return 0;
}