思路
淼淼题
考虑一个朴素的 DP:我们设 \(f_i\) 表示将 \([1,R_i]\) 的居民治好需要的最小代价
对于转移 \(f_i\longrightarrow f_j\),当且仅当 \(R_i-L_j+1\ge |T_j-T_i|\)
这是 \(O(n^2)\) 的;因为有取 \(\min\) 操作,我们考虑用最短路优化
观察式子,我们可以分两类讨论:
-
当 \(T_i\ge T_j\) 时,有 \(R_i-T_i+1\ge L_j-T_j\)
-
当 \(T_i < T_j\) 时,有 \(R_i+T_i+1\ge L_j+T_j\)
我们考虑建两棵线段树,每从一个点出发时,我们就在树上查询可以转移到的点
但这个复杂度似乎还是不对?
实际上,由于边权都是目标点的点权,结合 dijkstra
过程,当转移到目标点时,这个目标点一定就取到了最短路,因此每个点只会被转移一次
被转移后就在线段树上进行修改(改为 INF
)
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#define LL long long
#define FOR(i, x, y) for(int i = (x); i <= (y); i++)
#define ROF(i, x, y) for(int i = (x); i >= (y); i--)
#define PFOR(i, x) for(int i = he[x]; i; i = r[i].nxt)
inline int rd()
{
int sign = 1, re = 0; char c = getchar();
while(c < '0' || c > '9'){if(c == '-') sign = -1; c = getchar();}
while('0' <= c && c <= '9'){re = re * 10 + (c - '0'); c = getchar();}
return sign * re;
}
const int INF = 0x7fffffff;
int n, m, maxt;
struct Node
{
int t, l, r, c;
}a[100005]; LL ans = 1e18;
#define pli std::pair<LL, int>
std::priority_queue<pli, std::vector<pli>, std::greater<pli>> q;
LL ndis; std::bitset<100005> vis;
namespace Seg
{
#define ls (now << 1)
#define rs ((now << 1) | 1)
int Mn1[400005], Mn2[400005];
inline void up(int now) {Mn1[now] = std::min(Mn1[ls], Mn1[rs]), Mn2[now] = std::min(Mn2[ls], Mn2[rs]);}
void build(int now, int l, int r)
{
if(l == r) return void((Mn1[now] = a[l].l - a[l].t, Mn2[now] = a[l].l + a[l].t));
int mid = (l + r) >> 1;
build(ls, l, mid), build(rs, mid + 1, r);
up(now);
}
void queryL(int now, int l, int r, int to, int val)
{
if(Mn1[now] > val) return;
if(l == r)
{
q.push(pli(ndis + a[l].c, l));
Mn1[now] = Mn2[now] = INF;
return;
}
int mid = (l + r) >> 1;
queryL(ls, l, mid, to, val);
if(mid < to) queryL(rs, mid + 1, r, to, val);
up(now);
}
void queryR(int now, int l, int r, int to, int val)
{
if(Mn2[now] > val) return;
if(l == r)
{
q.push(pli(ndis + a[l].c, l));
Mn1[now] = Mn2[now] = INF;
return;
}
int mid = (l + r) >> 1;
if(to <= mid) queryR(ls, l, mid, to, val);
queryR(rs, mid + 1, r, to, val);
up(now);
}
}
inline void dij()
{
FOR(i, 1, m) if(a[i].l == 1)
q.push(pli(a[i].c, i));
while(!q.empty())
{
while(!q.empty() && vis[q.top().second]) q.pop();
if(q.empty()) break;
int now = q.top().second; ndis = q.top().first;
vis[now] = 1; q.pop();
if(a[now].r == n) ans = std::min(ans, ndis);
if(now > 1) Seg::queryL(1, 1, m, now - 1, a[now].r - a[now].t + 1);
if(now < m) Seg::queryR(1, 1, m, now + 1, a[now].r + a[now].t + 1);
}
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
#endif
n = rd(), m = rd();
FOR(i, 1, m) a[i] = (Node){rd(), rd(), rd(), rd()};
std::sort(a + 1, a + 1 + m, [&](Node a, Node b){return a.t < b.t;});
Seg::build(1, 1, m);
dij();
ans == 1e18 ? puts("-1") : printf("%lld", ans);
return 0;
}
标签:include,val,int,Day4,mid,rd,JOISC,2020,now
From: https://www.cnblogs.com/zuytong/p/16715943.html