P1250种树
题目链接:P1250 种树
题意
给你一条街,街由N个点构成,每个点上可以种一棵树,给你K个要求,每个要求由B,E,T组成,分别表示从点B开始到点E中间至少有T棵树,现在问这条街上最少有几颗树?
数据范围: 0 < N < = 3 ∗ 1 0 4 , 0 < K < = 5000 , 0 < B < = E < = 30000 0<N<=3*10^4,0<K<=5000,0<B<=E<=30000 0<N<=3∗104,0<K<=5000,0<B<=E<=30000
思路
设 sum[i]为到点i为止的前缀和。
将题目的意思稍加转换可得,求最小数量的sum[N],来使得所有要求满足 sum[E] - sum[B-1] >= T
这样就是求差分约束的问题了
我们可以利用最短路的计算公式, dis[u] + cost(u,v) >= dis[v]
来将其构造成一个最短路问题。即转换成 sum[E] + (-T) >= sum[B-1]
这样还不够,题目中还隐藏了一些信息,就是 每个点最多只能种一棵,每两个相邻的点,后面的点值必定大于前面的点值。
最后跑一边SPFA即可,但使用Djs好像会T。。。。。
代码
// luogu-judger-enable-o2
#include <bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for (int i = (int)j;i <= (int)k;i ++)
#define debug(x) cerr<<#x<<":"<<x<<endl
#define pb push_back
typedef long long ll;
const int MAXN = (int)1e6+7;
const int INF = (int)0x3f3f3f3f;
struct edge{
int v,cost;
edge(int v = 0,int cost = 0):v(v),cost(cost){}
};
vector<edge> G[MAXN];
int dis[MAXN];
void SPFA(int S) {
dis[S] = 0;
queue<int> qu;
qu.push(S);
while (!qu.empty()) {
int k = qu.front();qu.pop();
rep(i,0,G[k].size()-1) {
int v = G[k][i].v;
int co = G[k][i].cost;
if (dis[v] > dis[k] + co) {
dis[v] = dis[k] + co;
qu.push(v);
}
}
}
}
int main()
{
int N,M;
scanf("%d %d",&N,&M); memset(dis,0x3f,sizeof(int)*(N+2));
rep(i,1,M) {
int u,v,w;
scanf("%d %d %d",&u,&v,&w);
G[v].pb(edge(u-1,-w));
}
rep(i,1,N) {
G[i-1].pb(edge(i,1));
G[i].pb(edge(i-1,0));
}
SPFA(N);
int mn = INF;
rep(i,0,N) {
mn = min(mn,dis[i]);
}
int ans = dis[N]-mn;
printf("%d\n",ans);
}