[UOJ 87] #87. mx的仙人掌
#87. mx的仙人掌
题目大意
给出一个 \(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;
}