题意:
给定一个数轴上的n个区间,要求在数轴上选取最少的点使得第i个区间[ai,bi]里至少有ci个点。1<=n<=50000, 0<=ai<=bi<=50000, 1<=ci<=bi-ai+1。
思路:
记sum[i]表示数轴上[0,i]之间选点的个数,则对于第i个区间[ai,bi]需要满足sum[bi]-sum[ai-1]>=ci。同时需要保证sum有意义:0<=sum[i]-sum[i-1]<=1。
对于不等式xi-xj>=ck,从j到i连一条长度为ck的有向边,然后用spfa求最长路即可。最后的最小解就是sum[max{bi}]。
总结:
一道关于差分约束的题,构造不等式,化为有向边,然后最小解就跑最长路。坑点:最长路inf应为最小值,不等式的构造,以及spfa的起始点应该为min{ai}而不是0。
代码:
#include <iostream>
#include <queue>
using namespace std;
int n,a,b,c;
int inf=-100000;
//链式前向星
struct edge
{
int to,next,w;
};
edge e[510000];
int head[51000],tot;
int sum[51000];
bool vis[51000];
int maxbi=0,minai=51000;
void add(int x,int y,int w)
{
e[++tot].to=y,e[tot].next=head[x];
e[tot].w=w,head[x]=tot;
}
//求最长路
void spfa(int s)
{
queue<int> q;
q.push(s);
sum[s]=0,vis[s]=1;
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i!=0;i=e[i].next)
{
int v=e[i].to;
if(sum[v]<sum[u]+e[i].w)
{
sum[v]=sum[u]+e[i].w;
if(!vis[v])
{
q.push(v);
vis[v]=1;
}
}
}
}
}
int main()
{
cin>>n;
for(int i=0;i<51000;i++)
head[i]=0,sum[i]=inf,vis[i]=0;
tot=0;
for(int i=0;i<n;i++)
{
cin>>a>>b>>c;
maxbi=max(maxbi,b);
minai=min(minai,a);
//满足sum[b]-sum[a-1]>=c
//连接a-1~b,权重为c
add(a-1,b,c);
}
//0<=sum[i]-sum[i-1]<=1
//(i-1,i,0)和(i,i-1,-1)
for(int i=minai;i<=maxbi;i++)
add(i-1,i,0),add(i,i-1,-1);
spfa(minai-1);
cout<<sum[maxbi]<<endl;
}