H - 咸鱼睡觉觉
原题地址
大概题意:emmmmm…… 直接看题:
就是在 ai ~bi 间去除ci 只咕咕,问最少的咕咕数。
思路分析:涉及到区间,线段树?还是分块?貌似都不好解决。那么如何去做?差分约束。
简单说明一下,首先用 sum[ i ]表示区间的前缀和,那么 sum[ b ]-sum[ a-1 ]就是区间[ a,b ]的和,再看题目的约束条件:
sum[ bi ]-sum[ ai-1 ]>=ci ,除此之外,还有隐含条件:
0<=sum[ i ]-sum[ i-1 ]<=1; 那么这两个可以拆成3个不等式,我们可以想到什么?最短路的松弛操作。想一下,我们构建最短路的时候:dis[ v ]<=dis[ u ]+w[ u ][ v ],那么就是
dis[ u ]-dis[ v ]>= - w[ u ][ v ]. 所以总结就是求一下最短路即可。
核心代码:
1.
初始化,定义边结构体。这里用了前向星存储边。不再赘述。
2.
Spfa 求最短路。这里注意几点:这里的松弛操作就是不等式的转化;最后返回的是 -dis[ 0 ],因为我们改变不等式后路径上的权值之和是 -∑w ,而我们求的是 ∑w ,所以最后应该是 - dis[ 0 ]。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
struct Edge
{
int to;
int next;
int w;
}edge[500050];
int edgecount;
int head[50050];
int dis[50050];
bool vis[50050];
void init()
{
memset(head,-1,sizeof(head));
edgecount=0;
}
void add(int u,int v,int w)
{
edge[++edgecount].to=v;
edge[edgecount].w=w;
edge[edgecount].next=head[u];
head[u]=edgecount;
}
void spfa(int n)
{
memset(vis,0,sizeof(vis));
for(int i=0;i<=n;i++)dis[i]=inf;
dis[n]=0;
vis[n]=1;
queue<int> q;
q.push(n);
int cnt=1;
while(!q.empty()){
int u=q.front();
q.pop();
for(int k=head[u];k!=-1;k=edge[k].next){
int t=dis[u]+edge[k].w;
if(dis[edge[k].to]>t){
dis[edge[k].to]=t;
if(vis[edge[k].to])continue;
q.push(edge[k].to);
vis[edge[k].to]=1;
}
}
vis[u]=0;
}
cout<<-dis[0]<<endl;
}
int main()
{
int n,k;
scanf("%d%d",&k,&n);
int a,b,c;
init();
int maxn=0;
for(int i=1;i<=n;i++){
scanf("%d%d%d",&a,&b,&c);
a++,b++;
maxn=max(maxn,b);
add(b,a-1,-c);
}
for(int i=1;i<=maxn;i++){
add(i,i-1,0);
add(i-1,i,1);
}
spfa(maxn);
}