1 条题解
-
0
自动搬运
来自洛谷,原作者为

Ameyax
**搬运于
2025-08-24 22:00:48,当前版本为作者最后更新于2018-05-02 16:47:01,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
先放博客,
然后直接跑Bellman-Ford。换个角度,考虑每一个修路的点能更新到哪一些点,显然这是一个包含自己的连续区间。
那么对于一个修路的点,分别二分左右两个端点,以为例,令,如果这个区间内不存在点使得从这里出发到小于从出发到,那么这个就是可行的。
答案就是求
还要考虑边界问题防止重复计算,比如相同距离编号相近的更优先,相同距离编号差的绝对值也相同就左边优先。
rmq的实现方法也很重要,线段树很慢(没卡过去),我写的是用离散化后的st表。虽然两个复杂度都是的。还有二分查找用不要用库函数,时间有手写的两倍。
#include <bits/stdc++.h> using namespace std; int read() { int x = 0, f = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); } while (isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } #define ll long long const ll Max = 200033; const ll inf = 9999999999999999ll; ll n, m, now, K; ll dis[Max], pos[Max], len[Max], Ans; int bin[20], Log[Max]; struct Data { ll mn, id; Data() {} Data(ll a, ll b) { mn = a, id = b; } }; void init() { bin[0] = 1; for (int i = 1; i <= 18; i++) { bin[i] = bin[i - 1] << 1; Log[bin[i]] = i; } for (int i = 1; i < Max; i++) if (!Log[i]) Log[i] = Log[i - 1]; } struct ST { ll d[Max][18]; void init() { for (int j = 1; j <= Log[K]; j++) for (int i = 1; i <= K; i++) d[i][j] = min(d[i][j - 1], d[i + bin[j - 1]][j - 1]); } ll query(int L, int R) { int len = R - L + 1; return min(d[L][Log[len]], d[R - bin[Log[len]] + 1][Log[len]]); } } st[2]; int tmp[Max], t[Max]; int lower(int V) { int L = 1, R = K, re = K + 1; while (R >= L) { int mid = (L + R) >> 1; if (tmp[mid] < V) L = mid + 1; else R = mid - 1, re = mid; } return re; } int upper(int V) { int L = 1, R = K, re = K + 1; while (R >= L) { int mid = (L + R) >> 1; if (tmp[mid] <= V) L = mid + 1; else R = mid - 1, re = mid; } return re; } void solve() { for (int i = 1; i <= K; i++) tmp[i] = pos[i]; sort(tmp + 1, tmp + K + 1); for (int i = 1; i <= K; i++) t[tmp[i]] = i; for (int i = 1; i <= K; i++) { st[0].d[t[pos[i]]][0] = len[i] - dis[pos[i]]; st[1].d[t[pos[i]]][0] = len[i] + dis[pos[i]]; } st[0].init(), st[1].init(); Ans = 0; for (int i = 1; i <= K; i++) { int ql = 1, qr = pos[i] - 1, L = pos[i], R = L; while (qr >= ql) { bool flag = 1; int mid = (ql + qr) >> 1; ll nowdis = len[i] + dis[pos[i]] - dis[mid], idx = pos[i] - mid; ll dl = inf, dr = dl; int qql = lower(max(1ll, mid - idx)); int qqr = upper(mid) - 1; if (qql <= qqr) dl = st[0].query(qql, qqr); qql = lower(mid); qqr = upper(pos[i] - 1) - 1; if (qql <= qqr) dr = st[1].query(qql, qqr); if (dl + dis[mid] <= nowdis) flag = 0; if (dr - dis[mid] <= nowdis) flag = 0; if (flag) qr = mid - 1, L = mid; else ql = mid + 1; } ql = pos[i] + 1, qr = n; while (qr >= ql) { bool flag = 1; int mid = (ql + qr) >> 1; ll nowdis = len[i] + dis[mid] - dis[pos[i]], idx = mid - pos[i]; ll dl = inf, dr = dl; int qql = lower(mid); int qqr = upper(min(mid + idx - 1, n)) - 1; if (qql <= qqr) dr = st[1].query(qql, qqr); //cout << "fuck: " << mid << ' ' << dl << ' ' << dr << endl; qql = lower(pos[i] + 1); qqr = upper(mid) - 1; if (qql <= qqr) dl = st[0].query(qql, qqr); if (dl + dis[mid] <= nowdis) flag = 0; if (dr - dis[mid] <= nowdis) flag = 0; if (mid + idx <= n) { qqr = upper(min(mid + idx, n)) - 1; if (tmp[qqr] == mid + idx) if (st[1].d[qqr][0] - dis[mid] < nowdis) flag = 0; } if (flag) ql = mid + 1, R = mid; else qr = mid - 1; } Ans += (R - L + 1); } printf("%lld\n", Ans); } signed main() { init(); n = read(), m = read(); for (int i = 2; i <= n; i++) dis[i] = dis[i - 1] + read(); for (int i = 1; i <= m; i++) { K = read(); for (int j = 1; j <= K; j++) pos[j] = read(), len[j] = read(); solve(); } }
- 1
信息
- ID
- 3482
- 时间
- 3000ms
- 内存
- 512MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者