\(\mathcal{Description}\)

  Link.

  给出含 \(n\) 个结点 \(m\) 条边的仙人掌图。\(q\) 次询问,每次询问给出一个点集 \(S\),求 \(S\) 内两两结点最短距离的最大值。

  \(n,\sum|S|\le3\times10^5\)。

\(\mathcal{Solution}\)

  圆方树 + 虚树 = 虚圆方树!

  首先,考虑对于整个仙人掌怎么求答案:建出圆方树,DP 记录子树最深结点深度,在方点处单调队列合并圆儿子的两条链贡献答案即可。

  接下来,只需要把“虚圆方树”给弄出来就好。关键即在于满足方点周围一定裹着它自己管辖的圆点的性质,那么在建虚树边时特殊考虑一下就完成啦。

\(\mathcal{Code}\)

/* Clearink */

#include <cstdio>
#include <vector> #define rep( i, l, r ) for ( int i = l, repEnd##i = r; i <= repEnd##i; ++i )
#define per( i, r, l ) for ( int i = r, repEnd##i = l; i >= repEnd##i; --i ) inline char fgc() {
static char buf[1 << 17], *p = buf, *q = buf;
return p == q && ( q = buf + fread( p = buf, 1, 1 << 17, stdin ), p == q )
? EOF : *p++;
} inline int rint() {
int x = 0; char s = fgc();
for ( ; s < '0' || '9' < s; s = fgc() );
for ( ; '0' <= s && s <= '9'; s = fgc() ) x = x * 10 + ( s ^ '0' );
return x;
} template<typename Tp>
inline void wint( Tp x ) {
if ( x < 0 ) putchar( '-' ), x = -x;
if ( 9 < x ) wint( x / 10 );
putchar( x % 10 ^ '0' );
} typedef long long LL; template<typename Tp>
inline void chkmin( Tp& a, const Tp b ) { b < a && ( a = b ); }
template<typename Tp>
inline void chkmax( Tp& a, const Tp b ) { a < b && ( a = b ); }
inline LL lmin( const LL a, const LL b ) { return a < b ? a : b; } const int MAXN = 3e5, MAXM = MAXN << 1, MAXLG = 20;
const LL LINF = 1ll << 60;
int n, m; template<const int NODE, const int EDGE>
struct Graph {
int ecnt, head[NODE], to[EDGE], nxt[EDGE];
LL len[EDGE];
Graph(): ecnt( 1 ) {} inline void operator () ( const int s, const int t, const LL w ) {
#ifdef RYBY
printf( "%d %d %lld\n", s, t, w );
#endif
to[++ecnt] = t, len[ecnt] = w, nxt[ecnt] = head[s], head[s] = ecnt;
}
};
#define adj( t, u, v ) \
for ( int e = t.head[u], v; v = t.to[e], e; e = t.nxt[e] ) Graph<MAXN + 5, MAXM * 2 + 5> src; int vnode, dfc, dfn[MAXN * 2 + 5], low[MAXN + 5];
LL pre[MAXN * 2 + 5];
Graph<MAXN * 2 + 5, MAXN * 2 + 5> cac; inline void buildCactus( const int u, const int f ) {
static int top = 0, stk[MAXN + 5];
dfn[u] = low[u] = ++dfc, stk[++top] = u;
adj( src, u, v ) if ( v != f ) {
if ( !dfn[v] ) {
buildCactus( v, u );
chkmin( low[u], low[v] ); if ( low[v] >= dfn[u] ) {
cac( u, ++vnode, 0 ), pre[vnode] = src.len[e];
int las = u, ttop = top, cnt = 0;
do {
int w = stk[top];
for ( int i = src.head[w]; i; i = src.nxt[i] ) {
if ( i ^ e ^ 1 && src.to[i] == las ) {
++cnt;
pre[w] = pre[las] + src.len[i];
pre[vnode] += src.len[i];
break;
}
}
las = w;
} while ( stk[top--] != v ); do {
int w = stk[ttop];
cac( vnode, w, cnt ?
lmin( pre[w], pre[vnode] - pre[w] ) : pre[vnode] );
} while ( stk[ttop--] != v );
}
} else chkmin( low[u], dfn[v] );
}
} // `dfc` and `dfn` was used by `buildCactus`, pay attention.
int dep[MAXN * 2 + 5], fa[MAXN * 2 + 5][MAXLG + 5];
LL dis[MAXN * 2 + 5]; inline void initCactus( const int u ) {
dfn[u] = ++dfc;
for ( int i = 1; fa[u][i - 1]; fa[u][i] = fa[fa[u][i - 1]][i - 1], ++i );
adj( cac, u, v ) {
dep[v] = dep[u] + 1, dis[v] = dis[u] + cac.len[e], fa[v][0] = u;
initCactus( v );
}
} inline int lca( int u, int v ) {
if ( dep[u] < dep[v] ) u ^= v ^= u ^= v;
per ( i, MAXLG, 0 ) if ( dep[fa[u][i]] >= dep[v] ) u = fa[u][i];
if ( u == v ) return u;
per ( i, MAXLG, 0 ) if ( fa[u][i] != fa[v][i] ) u = fa[u][i], v = fa[v][i];
return fa[u][0];
} inline int climb( int u, const int par ) {
per ( i, MAXLG, 0 ) if ( dep[fa[u][i]] > dep[par] ) u = fa[u][i];
return u;
} Graph<MAXN * 2 + 5, MAXN * 2 + 5> virc; inline void vlink( int s, int t ) {
// s is t's ancestor in cactus tree.
if ( s > n ) {
int is = climb( t, s );
virc( s, is, dis[is] - dis[s] ), s = is;
}
if ( t > n ) {
virc( fa[t][0], t, dis[t] - dis[fa[t][0]] ), t = fa[t][0];
}
if ( s != t ) virc( s, t, dis[t] - dis[s] );
} inline void buildVirCac( std::vector<int>& vec ) {
static int top, stk[MAXN * 2 + 5];
virc.ecnt = 0, stk[top = 1] = 1; std::sort( vec.begin(), vec.end(), []( const int a, const int b ) {
return dfn[a] < dfn[b];
} ); for ( int u: vec ) if ( u != 1 ) {
int anc = lca( stk[top], u );
while ( dep[stk[top]] > dep[anc] ) {
int a = stk[top--], b = dep[stk[top]] < dep[anc] ? anc : stk[top];
vlink( b, a );
}
if ( stk[top] != anc ) stk[++top] = anc;
stk[++top] = u;
} while ( top > 1 ) {
int a = stk[top--], b = stk[top];
vlink( b, a );
}
} LL ans, f[MAXN * 2 + 5];
bool book[MAXN + 5]; inline void contri( const int u, const std::vector<int>& cir ) {
static int que[MAXN + 5], hd, tl;
int sz = int( cir.size() ); LL half = pre[u] >> 1; #define val( i ) ( pre[cir[i]] + ( i >= sz >> 1 ? pre[u] : 0 ) ) que[hd = tl = 1] = 0;
rep ( i, 1, sz - 1 ) {
while ( hd <= tl && val( i ) - val( que[hd] ) > half ) ++hd; if ( hd <= tl ) {
chkmax( ans, f[cir[que[hd]]] - val( que[hd] )
+ f[cir[i]] + val( i ) );
} while ( hd <= tl && f[cir[que[tl]]] - val( que[tl] )
<= f[cir[i]] - val( i ) ) --tl;
que[++tl] = i;
} #undef val
} inline void solve( const int u, const int par ) {
f[u] = -LINF;
adj( virc, u, v ) solve( v, u );
if ( u <= n ) {
LL mx = book[u] ? 0 : -LINF, sx = -LINF;
adj( virc, u, v ) {
if ( LL d = f[v] + virc.len[e]; d > mx ) sx = mx, mx = d;
else if ( d > sx ) sx = d;
}
chkmax( ans, mx + sx ), f[u] = mx;
} else {
static std::vector<int> cir; cir.clear(); LL tmpp = pre[par]; pre[par] = 0;
cir.push_back( par );
adj( virc, u, v ) cir.push_back( v );
int sz = int( cir.size() );
cir.resize( sz << 1 );
rep ( i, 0, sz - 1 ) cir[sz + i] = cir[i]; contri( u, cir );
pre[par] = tmpp; adj( virc, u, v ) chkmax( f[u], f[v] + virc.len[e] );
}
virc.head[u] = 0;
} int main() {
n = rint(), m = rint();
rep ( i, 1, m ) {
int u = rint(), v = rint(), w = rint();
src( u, v, w ), src( v, u, w );
} #ifdef RYBY
puts( "+++ +++ +++" );
#endif vnode = n, buildCactus( 1, 0 );
dfc = 0, dep[1] = 1, initCactus( 1 ); #ifdef RYBY
puts( "--- --- ---" );
#endif std::vector<int> vec;
for ( int q = rint(), k; q--; vec.clear() ) {
k = rint(), vec.resize( k );
rep ( i, 0, k - 1 ) book[vec[i] = rint()] = true;
buildVirCac( vec ); ans = 0, solve( 1, 0 );
wint( ans ), putchar( '\n' ); for ( int u: vec ) book[u] = false;
} return 0;
}

Solution -「UOJ #87」mx 的仙人掌的更多相关文章

  1. Solution -「UOJ #46」玄学

    \(\mathcal{Description}\)   Link.   给定序列 \(\{a_n\}\) 和 \(q\) 次操作,操作内容如下: 给出 \(l,r,k,b\),声明一个修改方案,表示 ...

  2. Solution -「UOJ #450」复读机

    \(\mathcal{Description}\)   Link.   求从 \(m\) 种颜色,每种颜色无限多的小球里选 \(n\) 个构成排列,使得每种颜色出现次数为 \(d\) 的倍数的排列方案 ...

  3. Solution -「ARC 104E」Random LIS

    \(\mathcal{Description}\)   Link.   给定整数序列 \(\{a_n\}\),对于整数序列 \(\{b_n\}\),\(b_i\) 在 \([1,a_i]\) 中等概率 ...

  4. Solution -「UNR #5」「UOJ #671」诡异操作

    \(\mathcal{Desciprtion}\)   Link.   给定序列 \(\{a_n\}\),支持 \(q\) 次操作: 给定 \(l,r,v\),\(\forall i\in[l,r], ...

  5. Solution -「JOISC 2020」「UOJ #509」迷路的猫

    \(\mathcal{Decription}\)   Link.   这是一道通信题.   给定一个 \(n\) 个点 \(m\) 条边的连通无向图与两个限制 \(A,B\).   程序 Anthon ...

  6. Solution -「UR #21」「UOJ #632」挑战最大团

    \(\mathcal{Description}\)   Link.   对于简单无向图 \(G=(V,E)\),定义它是"优美"的,当且仅当 \[\forall\{a,b,c,d\ ...

  7. Solution -「UR #2」「UOJ #32」跳蚤公路

    \(\mathcal{Description}\)   Link.   给定一个 \(n\) 个点 \(m\) 条边的带权有向图,每条边还有属性 \(s\in\{-1,0,1\}\).对于每个 \(u ...

  8. Solution -「CTS 2019」「洛谷 P5404」氪金手游

    \(\mathcal{Description}\)   Link.   有 \(n\) 张卡牌,第 \(i\) 张的权值 \(w_i\in\{1,2,3\}\),且取值为 \(k\) 的概率正比于 \ ...

  9. Solution -「BZOJ 3812」主旋律

    \(\mathcal{Description}\)   Link.   给定含 \(n\) 个点 \(m\) 条边的简单有向图 \(G=(V,E)\),求 \(H=(V,E'\subseteq E)\ ...

随机推荐

  1. python中addict模块,设置和读取嵌套字典

    源码地址:   https://github.com/mewwts/addict/blob/master/README.md

  2. Centos7 文件权限理解(持续更新)

    后期排版,边学边记边敲 用户详情分析 管理员用户 root  0 虚拟用户 nobody  1-999 普通用户 test001  1000+ 输入ll命令查看当前目录文件详情 根据这张图片可知,目录 ...

  3. Hive建表和内外部表的使用

    原文链接: https://www.toutiao.com/i6766784274965201415 一.普通建表方式 create table stu_info( id int, name stri ...

  4. Git 基础指令

    Git 基础指令 Git 基础指令 获取 Git 仓库 在已存在目录中初始化仓库 克隆现有的仓库 记录仓库与仓库的更新 仓库的记录 检查当前文件状态 三部曲 跟踪新文件 提交更新 移除文件 推送到远程 ...

  5. BootStrap 是什么东西?

    Bootstrap Bootstrap 能很快速搭建一整套页面.是最受欢迎的 HTML.CSS 和 JS 框架,用于开发响应式布局.移动设备优先的 WEB 项目.所有设备都可以适配.所有项目都适用.1 ...

  6. 一键AI着色,黑白老照片画面瞬间鲜活

    很多老照片或者电影受时代技术所限制,只能以黑白形式保存:经过编辑后的黑白视频和图片早已丢失彩色原图,这对于保存者来说都十分遗憾.如何能将单一乏味.陈旧斑驳的黑白照片变成鲜活亮丽的彩色照片,从照片中重新 ...

  7. pycharm创建脚本头文件模板

    代码头文件信息可以包括:python 解析器的位置.字符集.作者信息.创建脚本时间等,pycharm工具创建头部信息模板操作步骤如下: 设置头文件:文件-->设置-->编辑器-->文 ...

  8. Scala统计一个文件所有单词出现的次数

    1 import scala.io.Source 2 3 object WordCount extends App { 4 5 val path = "C:\\Users\\Administ ...

  9. 浅谈MySQL同步到ElasticSearch的几种方式及其优缺点

    同步双写 优点:业务逻辑简单. 缺点: 硬编码,有需要写入mysql的地方都需要添加写入ES的代码: 业务强耦合: 存在双写失败丢数据风险: 性能较差:本来mysql的性能不是很高,再加一个ES,系统 ...

  10. gin框架中的路由

    基本路由 gin框架中采用的路由库是基于httrouter做的 地址为:https://github.com/julienschmidt/httprouter httprouter路由库 点击查看代码 ...