[2021.8集训Day2/JZOJ.1254]清理牛棚
题目
思路
当每一个
S
S
S都比较大时,总费用可能超过
inf
\inf
inf,但是数据较水,这个问题可以自行解决.
线段树优化DP
T4竟是最水的一道题?!
设
f
i
f_i
fi表示前
i
i
i秒都有奶牛打扫的最小代价.显然,对于每一头奶牛,有
f
t
2
=
min
(
f
t
2
,
s
+
min
i
=
t
1
−
1
t
2
−
1
f
i
)
f_{t_2}=\min(f_{t_2},s+\min^{t_2-1}_{i=t_1-1}f_i)
ft2=min(ft2,s+i=t1−1mint2−1fi)
对于后面的取最小值,明显可以线段树优化.
把每一头奶牛按 t 2 t_2 t2递增排序再枚举即可.
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 10010 , M = 90000;
const int INF = 0x3fffffff;
int read() {
int re = 0;
char c = getchar();
bool negt = false;
while(c < '0' || c > '9')
negt |= (c == '-') , c = getchar();
while(c >= '0' && c <= '9')
re = (re << 1) + (re << 3) + c - '0' , c = getchar();
return negt ? -re : re;
}
class SegmentTreee {
private :
struct TreeNode {
int l , r , ls , rs , dat;
}node[M * 4];
int cnt;
public :
inline int newnode () {
return ++cnt;
}
int build(int l , int r) {
int id = newnode();
node[id].l = l , node[id].r = r , node[id].dat = INF;
if(l == r)
return id;
int mid = (l + r) / 2;
node[id].ls = build(l , mid);
node[id].rs = build(mid + 1 , r);
return id;
}
void change(int p , int pos , int dat) {
if(node[p].l == node[p].r) {
node[p].dat = dat;
return;
}
if(pos <= node[node[p].ls].r)
change(node[p].ls , pos , dat);
else
change(node[p].rs , pos , dat);
node[p].dat = min(node[node[p].ls].dat , node[node[p].rs].dat);
}
int query(int p , int l , int r) {
if(l <= node[p].l && r >= node[p].r)
return node[p].dat;
if(l > node[p].r || r < node[p].l)
return INF;
return min(query(node[p].ls , l , r) , query(node[p].rs , l , r));
}
}segT;
struct COW {
int st , end , cos;
}cow[N];
bool cmp(COW a , COW b) {
return a.end < b.end;
}
int n , m;
int root;
int cos[M];
int main() {
n = read();
int st = read() , end = read() , delta = st - 1;//需要打扫的时间:[1,m]
m = end - delta;
for(int i = 1 ; i <= n ; i++)
cow[i].st = read() - delta , cow[i].end = read() - delta , cow[i].cos = read();
sort(cow + 1 , cow + n + 1 , cmp);
root = segT.build(0 , m);
segT.change(root , 0 , 0);
memset(cos , 0x3f , sizeof(cos));
for(int i = 1 ; i <= n ; i++) {
int tmp = cow[i].cos + segT.query(root , cow[i].st - 1 , cow[i].end - 1);
if(tmp < cos[cow[i].end]) {
cos[cow[i].end] = tmp;
segT.change(root , cow[i].end , tmp);
}
}
cout << (cos[m] == 1061109567 ? -1 : cos[m]);
return 0;
}
最短路
**(这里的边都是有向边)**可以考虑建模,每一头奶牛 t 1 , t 2 , s t_1,t_2,s t1,t2,s从 t 1 − 1 t_1-1 t1−1到 t 2 t_2 t2连一条边权为 s s s的边,对于 E − 1 E-1 E−1到 M − 1 M-1 M−1的每一秒 i i i,从 i + 1 i+1 i+1到 i i i连一条边权为 0 0 0的边.从 E − 1 E-1 E−1出发, M M M结束,查询最短路即可
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
const int N = 10010 , M = 90000;
const int INF = 0x3fffffff;
int read() {
int re = 0;
char c = getchar();
bool negt = false;
while(c < '0' || c > '9')
negt |= (c == '-') , c = getchar();
while(c >= '0' && c <= '9')
re = (re << 1) + (re << 3) + c - '0' , c = getchar();
return negt ? -re : re;
}
struct EDGE {
int to , nxt , val;
}ed[M + N];
int head[M];
void addedge(int u , int v , int val) {
static int cnt = 0;
++cnt;
ed[cnt].to = v , ed[cnt].val = val , ed[cnt].nxt = head[u] , head[u] = cnt;
}
int n , m;
bool inq[M];
int dis[M];
void spfa() {//懒得写dij,勿喷SPFA QAQ
memset(dis , 0x3f , sizeof(dis));
dis[0] = 0;
queue <int> q;
inq[0] = true , q.push(0);
while(!q.empty()) {
int u = q.front();
inq[u] = false , q.pop();
for(int i = head[u] ; i ; i = ed[i].nxt) {
int v = ed[i].to;
if(dis[v] > dis[u] + ed[i].val) {
dis[v] = dis[u] + ed[i].val;
if(!inq[v])
inq[v] = true , q.push(v);
}
}
}
}
int main() {
n = read();
int st = read() , end = read() , delta = st - 1;
m = end - delta;
for(int i = 0 ; i < m ; i++)
addedge(i + 1 , i , 0);
for(int i = 1 ; i <= n ; i++) {
int u = read() - delta - 1 , v = read() - delta , val = read();
addedge(u , v , val);
}
spfa();
cout << (dis[m] == 1061109567 ? -1 : dis[m]);
return 0;
}