思路:我们考虑两个绿点之间的红点和蓝点, 首先把这些红点和蓝点接到绿点上面绝对不会超过绿点距离的两倍。
然后我们先把两个绿点连上, 再把绿点经过蓝点到绿点的线连上, 绿点经过红点到绿点的线连上, 这时距离为3倍的绿点间距离,
然后我们可以在第二条路径和第三条路径上断开一段最长的, 和两个的绿点距离取个最小值,就是这段的贡献。
#include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk make_pair #define PLL pair<LL, LL> #define PLI pair<LL, int> #define PII pair<int, int> #define SZ(x) ((int)x.size()) #define ull unsigned long long using namespace std; const int N = 3e5 + 7; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = 1e9 + 7; const double eps = 1e-8; int n, p, dis[N]; char s[3]; vector<int> G, R, B; int main() { scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%d%s", &p, s); if(s[0] == 'G') G.push_back(p); else if(s[0] == 'R') R.push_back(p); else B.push_back(p); } LL ans = 0; if(SZ(G)) { int S = G[0], T = G[SZ(G)-1]; if(SZ(R) && R[0] < S) ans += abs(R[0] - S); if(SZ(R) && R[SZ(R)-1] > T) ans += abs(R[SZ(R)-1] - T); if(SZ(B) && B[0] < S) ans += abs(B[0] - S); if(SZ(B) && B[SZ(B)-1] > T) ans += abs(B[SZ(B)-1] - T); for(int i = 0; i + 1 < SZ(G); i++) { LL l = G[i], r = G[i + 1]; LL ret = 0, tmp1 = INF, tmp2 = INF; int x = lower_bound(R.begin(), R.end(), l) - R.begin(); int y = lower_bound(R.begin(), R.end(), r) - R.begin() - 1; if(x <= y) { tmp1 = min(tmp1, r-l-(R[x]-l)); tmp1 = min(tmp1, r-l-(r-R[y])); for(int j = x; j < y; j++) tmp1 = min(tmp1, r-l-(R[j+1]-R[j])); } else tmp1 = 0; x = lower_bound(B.begin(), B.end(), l) - B.begin(); y = lower_bound(B.begin(), B.end(), r) - B.begin() - 1; if(x <= y) { tmp2 = min(tmp2, r-l-(B[x]-l)); tmp2 = min(tmp2, r-l-(r-B[y])); for(int j = x; j < y; j++) tmp2 = min(tmp2, r-l-(B[j+1]-B[j])); } else tmp2 = 0; ans += min(2 * (r - l), tmp1 + tmp2 + r - l); } } else { if(SZ(R)) ans += R[SZ(R)-1] - R[0]; if(SZ(B)) ans += B[SZ(B)-1] - B[0]; } printf("%lld ", ans); return 0; } /* */