\(\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. PPT2010制作图片玻璃磨砂效果

    原文链接: https://www.toutiao.com/i6488928834799272462/ 选择"插入"选项卡,"图像"功能组,"图片&q ...

  2. println打印的原理

    由于out是System类中的一个不可变的变量 println方法在PrintStream类中 并且在打印都时候都会转换成字符串

  3. 【C语言】将文本中汉字读入字符数组输出乱码

    输出中文字符乱码 今天从文件中将中文读入字符数组后输出发现其中文变成了乱码,,令人头大. 解决办法 将文本编码格式改成ANSI即可. 打开记事本->文件->另存为->更改编码格式-& ...

  4. python2.7发送邮件失败之——SMTPAuthenticationError问题

    使用python2.7发送邮件,代码如下: from email.header import Headerfrom email.mime.text import MIMETextimport smtp ...

  5. Android官方文档翻译 十三 3.1Supporting Different Languages

    Supporting Different Languages 支持不同语言 This class teaches you to 这节课教给你 Create Locale Directories and ...

  6. python实现--九九乘法表

    1 for i in range(1,10): 2 for j in range(1,i+1): 3 print("%d*%d=%d"%(j,i,j*i),end="\t ...

  7. dubbo 实现简易分布式服务

    dubbo 实现简易分布式服务 服务器需要搭建zookeeper环境 zookeeper端口2181 还需要有java环境 1.需求 某个电商系统,订单服务需要调用用户服务获取某个用户的所有地址: 我 ...

  8. [JavaWeb]反序列化分析(二)--CommonCollections1

    反序列化分析(二)--CommonCollections1 链子分析 首先新建一个TransformedMap,其中二三参数为可控,后续要用到 当TransformedMap执行put方法时,会分别执 ...

  9. 看看CSDN的吃相

    大伙快来看看CSDN的吃相.

  10. 观察者模式(Observer模式)

    模式的定义与特点 观察者(Observer)模式的定义:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新.这种模式有时又称作发布-订阅模式.模型- ...