博主的 BiBi 时间

今天考试全线炸裂。这道 \(T_1\) 连电风扇的分都没拿到(我竟然还专门思考了一波不用线段树 qwq

Description

\(\text{Link.}\)

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;
}
posted on 2020-06-06 16:34  Oxide  阅读(251)  评论(0)    收藏  举报