P5344 【XR-1】逛森林[倍增优化建图,zkw线段树优化spfa]

判下连通,离线下来连边,就是个裸的板子了QvQ。
我们把一堆边连到一个点,那个点连到一堆边,这样就可以满足 [l1,r1] -> to [l2,r2] 了
可以用 zkw 线段树来跑 spfa,奇怪的姿势增加了。

// by Isaunoya
#include<bits/stdc++.h>
using namespace std;
struct io {
	char buf[1 << 25 | 3], *s;
	int f;
	io() { f = 0, buf[fread(s = buf, 1, 1 << 25, stdin)] = '\n'; }
	io& operator >> (int&x) {
		for(x = f = 0; !isdigit(*s); ++s) f |= *s  == '-';
		while(isdigit(*s)) x = x * 10 + (*s++ ^ 48);
		return x = f ? -x : x, *this;
	}
};

struct io_out {
	char buf[1 << 25 | 3], *s = buf;
	~io_out() { fwrite(buf, 1, s - buf, stdout); }
	void write(int x) { if(x > 9) write(x / 10); *s++ = x % 10 ^ '0'; }
	io_out& operator << (int x) {
		if(x < 0) x = -x, *s++ = '-';
		write(x); return *this;
	}
	io_out& operator << (char x) { *s++ = x; return *this; }
} out;

int n, m, s;
const int maxn = 1e6 + 61;
const int maxd = maxn << 5;
struct dsu {
	int fa[maxn];
	dsu() { for(int i = 0 ; i < maxn ; i ++) fa[i] = i; }
	int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
	int operator [](int x) { return find(x); }
} dsu;
struct edge { int v, nxt, w; } e[maxd << 1]; int head[maxd], cnt = 0;
void add(int u, int v, int w) { e[++ cnt] = { v, head[u], w }, head[u] = cnt; }

int dfn[maxn], f[maxn][22], idx = 0, dep[maxn];
pair <int, int> st[maxn << 1][22];

void dfs(int u) {
	dfn[u] = ++ idx; st[idx][0] = make_pair(dep[u], u);
	for(int i = head[u]; i; i = e[i].nxt) {
		int v = e[i].v;
		if(v == f[u][0]) continue;
		f[v][0] = u; dep[v] = dep[u] + 1; dfs(v);
		st[++ idx][0] = make_pair(dep[u], u);
	}
}

int lg[maxn << 1];
int lca(int u, int v) {
	if((u = dfn[u]) > (v = dfn[v])) u ^= v ^= u ^= v;
	int len = v - u + 1; len = lg[len];
	return min(st[u][len], st[v - (1 << len) + 1][len]).second;
}

int id1[maxn][22], id2[maxn][22]; 
void link1(int u, int v, int t, int w) {
	int len = dep[u] - dep[v] + 1;
	int x = id1[u][lg[len]];
	int x2 = u, res = len - (1 << lg[len]);
	for(; res; res ^= res & - res)
		x2 = f[x2][lg[res & -res]];
	x2 = id1[x2][lg[len]];
	add(x, t, w), add(x2, t, w);
}

void link2(int u, int v, int t, int w) {
	int len = dep[u] - dep[v] + 1;
	int x = id2[u][lg[len]];
	int x2 = u, res = len - (1 << lg[len]);
	for(; res; res ^= res & - res)
		x2 = f[x2][lg[res & -res]];
	x2 = id2[x2][lg[len]];
	add(t, x, w), add(t, x2, w);
}

struct que { int u1, v1, u2, v2, w; } q[maxn];
int t = 0, nd = 0;

int dis[maxd];
struct zkw_segment_tree {
	int l, s[maxd << 1];
	zkw_segment_tree() { l = 1; }
	
	void build() {
		while(l < nd) l <<= 1; --l;
		for(int i = 1 ; i <= nd ; i ++) s[i + l] = i;
	}
	
	void upd(int x) {
		x += l; x >>= 1;
		while(x) {
			s[x] = dis[s[x << 1]] < dis[s[x << 1 | 1]] ? s[x << 1] : s[x << 1 | 1];
			x >>= 1;
		}
	}
	void del(int x) { s[x + l] = 0; upd(x); }
} zkw;

void spfa(int u) {
	memset(dis, 0x3f, sizeof(dis));
	dis[u] = 0; zkw.build(), zkw.upd(u);
//	out << u << '\n';
//	out << zkw.s[1] << '\n';
//	out << dis[zkw.s[1]] << '\n';
	while(dis[zkw.s[1]] != 0x3f3f3f3f) {
		int u = zkw.s[1];
		zkw.del(u);
//		out << u << '\n';
		for(int i = head[u]; i; i = e[i].nxt) {
			int v = e[i].v;
			if(dis[u] + e[i].w < dis[v]) { dis[v] = dis[u] + e[i].w; zkw.upd(v); }
		}
	}
//	out << '\n';
}

signed main() {
#ifdef LOCAL
	freopen("testdata.in", "r", stdin);
#endif
	io in;
	in >> n >> m >> s;
	for(int i = 1 ; i <= m ; i ++) {
		int op, u1, v1, u2, v2, w;
		in >> op;
		if(op == 1) {
			in >> u1 >> v1 >> u2 >> v2 >> w;
			if(dsu[u1] ^ dsu[v1] || dsu[u2] ^ dsu[v2])
				continue;
			q[++ t] = { u1, v1, u2, v2, w };
		} else {
			in >> u1 >> v1 >> w;
			int fx = dsu[u1], fy = dsu[v1];
			if(fx == fy) continue; add(u1, v1, w), add(v1, u1, w);
			dsu.fa[fy] = fx;
		}
	}
	for(int i = 1 ; i <= n ; i ++) if(!dfn[i]) dep[i] = 1, dfs(i);
	lg[0] = -1; for(int i = 1 ; i <= idx ; i ++) lg[i] = lg[i >> 1] + 1;
//	for(int i = 1 ; i <= n ; i ++)
//		out << f[i][0] << '\n';
	for(int j = 1 ; j <= 20 ; j ++)
		for(int i = 1 ; i <= n ; i ++) f[i][j] = f[f[i][j - 1]][j - 1];
	for(int j = 1 ; j <= 20 ; j ++)
		for(int i = 1 ; i + (1 << j) - 1 <= idx ; i ++)
			st[i][j] = min(st[i][j - 1], st[i + (1 << j - 1)][j - 1]);
	nd = n;
	for(int i = 1 ; i <= n ; i ++) id1[i][0] = id2[i][0] = i;
	for(int j = 1 ; j <= 20 ; j ++) {
		for(int i = 1 ; i <= n ; i ++) {
			if((1 << j) <= dep[i]) {
				id1[i][j] = ++nd, id2[i][j] = ++nd;
				add(id1[i][j - 1], id1[i][j], 0);
				add(id1[f[i][j - 1]][j - 1], id1[i][j], 0);
				add(id2[i][j], id2[i][j - 1], 0);
				add(id2[i][j], id2[f[i][j - 1]][j - 1], 0);
			}
		}
	}
	for(int i = 1 ; i <= t ; i ++) {
		int u1, v1, u2, v2, w;
		u1 = q[i].u1, v1 = q[i].v1, u2 = q[i].u2, v2 = q[i].v2, w = q[i].w;
		int u = ++nd, l1 = lca(u1, v1), l2 = lca(u2, v2);
		link1(u1, l1, u, w);
		if(v1 ^ l1) link1(v1, l1, u, w);
		link2(u2, l2, u, 0);
		if(v2 ^ l2) link2(v2, l2, u, 0);
	}
	spfa(s);
	for(int i = 1 ; i <= n ; i ++)
		if(dis[i] == dis[0]) 
			out << -1 << ' ';
		else
			out << dis[i] << ' ';
	return 0;
}

posted @ 2020-05-02 17:47  _Isaunoya  阅读(195)  评论(0编辑  收藏  举报