[UOJ 87] #87. mx的仙人掌

#87. mx的仙人掌

UOJ 87

1

题目大意

给出一个 \(n\) 个点,\(m\) 条边的带边权的仙人掌,定义两点之间距离为最短路长度,\(Q\) 次询问,每次给出 \(cnt\) 个点,问它们之间最远点对的距离。

数据范围

边权不超过 \(2^{31} - 1\)

\(n, \sum cnt \le 300000\)

时空限制

5s, 512MB

分析

此题如果不是仙人掌,那就是每次建出虚树来 DP

仙人掌求最短路也就是建出圆方树后根据 \(lca\) 分类讨论,那么,我们就根据圆方树建一个虚树,如果当前节点是圆点那么就和树的情况 ,如果当前节点为方点那么它的儿子提出来,在环上用单调队列更新答案即可

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <vector>
using namespace std;
inline char nc() {
	return getchar();
	static char buf[100000], *l = buf, *r = buf;
	return l==r&&(r=(l=buf)+fread(buf,1,100000,stdin),l==r)?EOF:*l++;
}
template<class T> void read(T & x) {
	x = 0; int f = 1, ch = nc();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=nc();}
	while(ch>='0'&&ch<='9'){x=x*10-'0'+ch;ch=nc();}
	x *= f;
}
typedef long long ll;
const int maxn = 300000 + 5;
const int maxm = maxn * 2;
const int maxe = maxm * 2;
const int maxnode = maxn * 2;
const int maxlog = 20;
const int sigma_cnt = 300000 + 5;
int n, m, Q, cnt, p[sigma_cnt]; ll an;
int sta[sigma_cnt], que[sigma_cnt << 1];
ll f[maxnode];
int head[maxnode], ecnt;
int dfc, dfn[maxnode], low[maxn], anc[maxn]; ll dist[maxn];
int dep[maxnode], parent[maxnode][maxlog]; ll dis[maxnode];
int bcnt; ll sum[maxn];
map<int, int> E[maxn];
vector<int> adj[maxnode];
struct edge {
	int to, nex; ll cost;
	edge(int to=0, int nex=0, ll cost=0) : to(to), nex(nex), cost(cost) {}
} g[maxe];
inline void addedge1(int u, int v, int w) {
	if(E[u].count(v)) E[u][v] = min(E[u][v], w); else E[u][v] = w;
	if(E[v].count(u)) E[v][u] = min(E[v][u], w); else E[v][u] = w;
}
inline void addedge2(int u, int v, ll w) {
	g[ecnt] = edge(v, head[u], w), head[u] = ecnt++;
	g[ecnt] = edge(u, head[v], w), head[v] = ecnt++;
}
inline void addedge3(int u, int v) {
	adj[u].push_back(v);
}
void tarjan(int u) {
	low[u] = dfn[u] = ++dfc;
	for(map<int, int> :: iterator it = E[u].begin(); it != E[u].end(); ++it) {
		int v = it->first;
		if(!dfn[v]) {	
			dist[v] = dist[u] + it->second;
			anc[v] = u; tarjan(v);
			low[u] = min(low[u], low[v]);
			if(low[v] > dfn[u]) {
				addedge2(u, v, it->second);
			}
		}
		else if(anc[u] != v) {
			low[u] = min(low[u], dfn[v]);
		} 
	}
	for(map<int, int> :: iterator it = E[u].begin(); it != E[u].end(); ++it) {
		int v = it->first;
		if(anc[v] != u && dfn[v] >= dfn[u]) {
			int now = ++bcnt; sum[now] = dist[v] - dist[u] + it->second;
			for(int x = v; ; x = anc[x]) {
				ll t = dist[x] - dist[u]; addedge2(now + n, x, min(t, sum[now] - t));
				if(x == u) break;
			}
		}
	}
}
void dfs(int u) {
	dfn[u] = ++dfc;
	for(int i = 1; i < maxlog; ++i) {
		parent[u][i] = parent[ parent[u][i - 1] ][i - 1];
	}
	for(int i = head[u]; ~ i; i = g[i].nex) {
		int v = g[i].to; if(v == parent[u][0]) continue;
		dep[v] = dep[u] + 1, dis[v] = dis[u] + g[i].cost;
		parent[v][0] = u; dfs(v);
	}
}
void jump(int & u, int k) {
	for(int i = maxlog - 1; ~ i; --i) {
		if(k >= (1 << i)) {
			k -= 1 << i;
			u = parent[u][i];
		}
	}
}
int lca(int u, int v) {
	if(dep[u] > dep[v]) swap(u, v);
	jump(v, dep[v] - dep[u]);
	if(u == v) return u;
	for(int i = maxlog - 1; ~ i; --i) {
		if(parent[u][i] != parent[v][i]) {
			u = parent[u][i];
			v = parent[v][i];
		}
	}
	return parent[u][0];
}
void update(int u, int n) {
	static ll f[sigma_cnt << 1], g[sigma_cnt << 1];
	for(int i = 1; i <= n; ++i) {
		f[i] = dist[ sta[i] ], f[n + i] = f[i] + sum[u - ::n];
		g[i] = ::f[ sta[i] ], g[n + i] = g[i];
	}
	n <<= 1; int l = 0, r = -1;
	for(int i = 1; i <= n; ++i) {
		while(l <= r && (f[i] - f[ que[l] ]) * 2 > sum[u - ::n]) l++;
		if(l <= r) an = max(an, g[ que[l] ] - f[ que[l] ] + g[i] + f[i]);
		while(l <= r && g[ que[r] ] - f[ que[r] ] <=  g[i] - f[i]) r--;
		que[++r] = i;
	}
}
void dp(int u) {
	f[u] = 0; int top = 0;
	for(unsigned int i = 0; i < adj[u].size(); ++i) {
		int v = adj[u][i]; dp(v);
	}
	for(unsigned int i = 0; i < adj[u].size(); ++i) {
		int v = adj[u][i];
		if(u <= n) an = max(an, f[u] + f[v] + dis[v] - dis[u]);
		else {
			int s = v; jump(s, dep[v] - dep[u] - 1);
			f[s] = f[v] + dis[v] - dis[s]; sta[++top] = s;
		}
		f[u] = max(f[u], f[v] + dis[v] - dis[u]);

	}
	if(u > n) update(u, top);
	adj[u].clear();
}
int cmp(const int & a, const int & b) {
	return dfn[a] < dfn[b];
}
void solve() {
	read(cnt);
	for(int i = 1; i <= cnt; ++i) read(p[i]);
	sort(p + 1, p + cnt + 1, cmp), cnt = unique(p + 1, p + cnt + 1) - p - 1;
	int top = 0; sta[++top] = p[1];
	for(int i = 2; i <= cnt; ++i) {
		int w = lca(sta[top], p[i]);
		while(top > 1 && dep[ sta[top - 1] ] > dep[w]) {
			addedge3(sta[top - 1], sta[top]); top--;
		}
		if(dep[sta[top]] > dep[w]) addedge3(w, sta[top--]);
		if(w != sta[top]) sta[++top] = w;
		sta[++top] = p[i];
	}
	while(top > 1) {
		addedge3(sta[top - 1], sta[top]); top--;
	}
	an = 0; dp(sta[top]); printf("%lld\n", an);
}
int main() {
	read(n), read(m);
	for(int i = 1; i <= m; ++i) {
		int u, v, w;
		read(u), read(v), read(w);
		addedge1(u, v, w);
	}
	memset(head, -1, sizeof(head)); tarjan(1);
	for(int i = 1; i <= n; ++i) E[i].clear(); 
	dfc = 0; dfs(1);
	read(Q);
	for(int i = 1; i <= Q; ++i) solve();
	return 0;
}
posted @ 2019-01-08 23:12  LJZ_C  阅读(370)  评论(0编辑  收藏  举报