博主的 BiBi 时间
今天考试全线炸裂。这道 \(T_1\) 连电风扇的分都没拿到(我竟然还专门思考了一波不用线段树 qwq
Description
Solution
非常巧妙的转化!
可以将区间 \([l,r]\) 的操作理解成差分:在模二意义下,把 \(c_l\) 加一,把 \(c_{r+1}\) 加一。
设 \(l_i,r_i\) 分别为第 \(i\) 段的起点与终点。最后我们的目标是 \(c_{l_2}=c_{r_2+1}=c_{l_4}=c_{r_4+1}=1\),而其它数字都为零。
事实上我们可以把这个玩意转化成图论问题:对于操作 \([l,r]\),连接一条 \(\langle l,r+1 \rangle\) 的 无向边,边权为 \(r-l+1\). 我们惊喜地发现,对于一条 连续的路径 \(x\rightarrow y\ \ (x\neq y)\),只可能使 \(c_x,c_y\) 的值发生改变。为啥捏?考虑除了 \(x,y\) 这两个点,其它的点的度数均为偶,而度数代表着加一的次数。
所以我们只需要找出两条路径,端点在 \(l_2,r_2+1,l_4,r_4+1\) 中选取就好了,显然有三种情况。对于每条路径,跑一个最短路即可。
Code
#include <queue>
#include <cstdio>
#include <iostream>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
const ll inf = 1e18;
int n, a[10], nxt[N << 1], to[N << 1], head[N * 5], cnt;
ll ans = inf, dis[N * 5], w[N << 1];
bool vis[N * 5];
struct node {
ll w; int id;
node() {}
node(const ll W, const int Id) {w = W; id = Id;}
bool operator < (const node x) const {
return w > x.w;
}
};
priority_queue <node> q;
int read() {
int x = 0, f = 1; char s;
while((s = getchar()) > '9' || s < '0') if(s == '-') f = -1;
while(s <= '9' && s >= '0') x = (x << 1) + (x << 3) + (s ^ 48), s = getchar();
return x * f;
}
void addEdge(const int u, const int v, const ll val) {
nxt[++ cnt] = head[u], to[cnt] = v, w[cnt] = val, head[u] = cnt;
}
ll Dijkstra(const int s, const int t) {
for(int i = 1; i <= a[5] + 1; ++ i) dis[i] = inf, vis[i] = 0;
dis[s] = 0;
q.push(node(0, s));
while(! q.empty()) {
int u = q.top().id; q.pop();
if(vis[u]) continue;
vis[u] = 1;
for(int i = head[u]; i; i = nxt[i])
if(dis[to[i]] > dis[u] + w[i]) dis[to[i]] = dis[u] + w[i], q.push(node(dis[to[i]], to[i]));
}
return dis[t] == inf ? -1 : dis[t];
}
int main() {
int u, v; ll r1, r2;
for(int i = 1; i <= 5; ++ i) a[i] = read() + a[i - 1];
n = read();
for(int i = 1; i <= n; ++ i) {
u = read(), v = read();
addEdge(u, v + 1, v - u + 1), addEdge(v + 1, u, v - u + 1);
}
r1 = Dijkstra(a[1] + 1, a[2] + 1), r2 = Dijkstra(a[3] + 1, a[4] + 1);
if(r1 != -1 && r2 != -1) ans = min(ans, r1 + r2);
r1 = Dijkstra(a[1] + 1, a[3] + 1), r2 = Dijkstra(a[2] + 1, a[4] + 1);
if(r1 != -1 && r2 != -1) ans = min(ans, r1 + r2);
r1 = Dijkstra(a[1] + 1, a[4] + 1), r2 = Dijkstra(a[2] + 1, a[3] + 1);
if(r1 != -1 && r2 != -1) ans = min(ans, r1 + r2);
printf("%lld\n", ans == inf ? -1 : ans);
return 0;
}