\(\mathcal{Description}\)

  Link.

  给定一个 \(n\) 个点 \(m\) 条边的无向连通图,\(q\) 次询问,每次给出一个点集 \(s\),求至少在原图中删去多少个点,使得 \(s\) 中存在两点不连通。多组数据。

  每组数据 \(n,q\le10^5\),\(m,\sum|s|\le2\times10^5\)。

\(\mathcal{Solution}\)

  看到 \(\sum|s|\) 的限制,不难联想到虚树或者其它与 DFN 相关的算法。

  所以,先建出圆方树,并处理好 DFN,LCA 的一系列信息。考虑到答案就是 \(s\) 中的点在树上构成的连通块中不在 \(s\) 集合里的圆点个数,可以求一个树上前缀和:\(sum_u\) 表示从 \(u\) 到根路径上的圆点个数。处理询问时,先将 \(s\) 按 DFN 从小到大排序,两两 LCA 计算贡献(\(s_1\) 和 \(s_{|s|}\) 也要算一次),最后除以 \(2\),得到 \(cnt\)。不过整个连通块的根(\(\operatorname{LCA}(s_1,s_{|s|})\))这个点的贡献被遗漏了,所以要再加上这个点单独的贡献。最终答案就是 \(cnt-|s|\)。

  复杂度 \(\mathcal O(T(n\log n+\sum|s|\log\sum|s|))\)。

\(\mathcal{Code}\)

  就是练练码力的一道题嘛 qwq。

  1. #include <queue>
  2. #include <cstdio>
  3. #include <algorithm>
  4. #define adj( g, u, v ) \
  5. for ( int eid = g.head[u], v; v = g.to[eid], eid; eid = g.nxt[eid] )
  6. const int MAXN = 2e5, MAXM = 4e5;
  7. int n, m, q, snode;
  8. int dfc, top, dfn[MAXN + 5], low[MAXN + 5], stk[MAXN + 5];
  9. int lg[MAXN * 2 + 5], dep[MAXN + 5], st[MAXN * 2 + 5][20], sum[MAXN + 5];
  10. struct Graph {
  11. int ecnt, head[MAXN + 5], to[MAXM + 5], nxt[MAXM + 5];
  12. inline void link ( const int s, const int t ) {
  13. to[++ ecnt] = t, nxt[ecnt] = head[s];
  14. head[s] = ecnt;
  15. }
  16. inline void add ( const int u, const int v ) {
  17. link ( u, v ), link ( v, u );
  18. }
  19. inline void clear () {
  20. ecnt = 0;
  21. for ( int i = 1; i <= n << 1; ++ i ) head[i] = 0;
  22. }
  23. } src, tre;
  24. inline int rint () {
  25. int x = 0; char s = getchar ();
  26. for ( ; s < '0' || '9' < s; s = getchar () );
  27. for ( ; '0' <= s && s <= '9'; s = getchar () ) x = x * 10 + ( s ^ '0' );
  28. return x;
  29. }
  30. inline bool chkmin ( int& a, const int b ) { return b < a ? a = b, true : false; }
  31. inline void clear () {
  32. src.clear (), tre.clear ();
  33. dfc = top = snode = 0;
  34. for ( int i = 1; i <= n << 1; ++ i ) dfn[i] = low[i] = 0;
  35. }
  36. inline void Tarjan ( const int u, const int f ) {
  37. dfn[u] = low[u] = ++ dfc, stk[++ top] = u;
  38. adj ( src, u, v ) if ( v ^ f ) {
  39. if ( ! dfn[v] ) {
  40. Tarjan ( v, u ), chkmin ( low[u], low[v] );
  41. if ( low[v] >= dfn[u] ) {
  42. tre.add ( u, ++ snode );
  43. do tre.add ( snode, stk[top] ); while ( stk[top --] ^ v );
  44. }
  45. } else chkmin ( low[u], dfn[v] );
  46. }
  47. }
  48. inline void initDFN ( const int u, const int f ) {
  49. dep[st[dfn[u] = ++ dfc][0] = u] = dep[f] + 1, sum[u] = sum[f] + ( u <= n );
  50. adj ( tre, u, v ) if ( v ^ f ) initDFN ( v, u ), st[++ dfc][0] = u;
  51. }
  52. inline void initST () {
  53. for ( int i = 2; i <= n << 2; ++ i ) lg[i] = lg[i >> 1] + 1;
  54. for ( int j = 1; 1 << j <= dfc; ++ j ) {
  55. for ( int i = 1; i + ( 1 << j ) - 1 <= dfc; ++ i ) {
  56. if ( dep[st[i][j - 1]] < dep[st[i + ( 1 << j >> 1 )][j - 1]] ) st[i][j] = st[i][j - 1];
  57. else st[i][j] = st[i + ( 1 << j >> 1 )][j - 1];
  58. }
  59. }
  60. }
  61. inline int calcLCA ( int u, int v ) {
  62. if ( dfn[u] > dfn[v] ) u ^= v ^= u ^= v;
  63. int k = lg[dfn[v] - dfn[u] + 1];
  64. return dep[st[dfn[u]][k]] < dep[st[dfn[v] - ( 1 << k ) + 1][k]] ?
  65. st[dfn[u]][k] : st[dfn[v] - ( 1 << k ) + 1][k];
  66. }
  67. inline void solve () {
  68. static int cnts, s[MAXN + 5];
  69. cnts = rint ();
  70. for ( int i = 1; i <= cnts; ++ i ) s[i] = rint ();
  71. std::sort ( s + 1, s + cnts + 1, []( const int a, const int b ) { return dfn[a] < dfn[b]; } );
  72. int cnt = 0;
  73. for ( int i = 1; i < cnts; ++ i ) {
  74. int u = s[i], v = s[i + 1], t = calcLCA ( u, v );
  75. cnt += sum[u] + sum[v] - 2 * sum[t];
  76. }
  77. int u = s[1], v = s[cnts], t = calcLCA ( u, v );
  78. cnt += sum[u] + sum[v] - 2 * sum[t];
  79. cnt /= 2, cnt += ( t <= n ) - cnts;
  80. printf ( "%d\n", cnt );
  81. }
  82. int main () {
  83. for ( int T = rint (); T --; clear () ) {
  84. n = snode = rint (), m = rint ();
  85. for ( int i = 1, u, v; i <= m; ++ i ) {
  86. u = rint (), v = rint ();
  87. src.add ( u, v );
  88. }
  89. Tarjan ( 1, 0 ), dfc = 0;
  90. initDFN ( 1, 0 ), initST ();
  91. for ( q = rint (); q --; ) solve ();
  92. }
  93. return 0;
  94. }

Solution -「SDOI 2018」「洛谷 P4606」战略游戏的更多相关文章

  1. 洛谷P4606 [SDOI2018]战略游戏 【圆方树 + 虚树】

    题目链接 洛谷P4606 双倍经验:弱化版 题解 两点之间必经的点就是圆方树上两点之间的圆点 所以只需建出圆方树 每次询问建出虚树,统计一下虚树边上有多少圆点即可 还要讨论一下经不经过根\(1\)的情 ...

  2. 洛谷P4606 [SDOI2018]战略游戏 [广义圆方树]

    传送门 思路 先考虑两点如何使他们不连通. 显然路径上所有的割点都满足条件. 多个点呢?也是这样的. 于是可以想到圆方树.一个点集的答案就是它的虚树里圆点个数减去点集大小. 可以把点按dfs序排序,然 ...

  3. 【洛谷P2016】战略游戏

    题面 题解 树形\(dp\)(最大独立集) 设\(f_{i,0/1}\)表示\(dp\)到第\(i\)个点,在这个点放了(没放)士兵的最小花费 直接转移即可. 代码 #include<cstdi ...

  4. 洛谷4606 SDOI2018战略游戏(圆方树+虚树)

    QWQ深受其害 当时在现场是真的绝望...... 现在再重新来看这个题 QWQ 根据题目所说,我们可以发现,对于每一个集合中的节点,我们实际上就是要求两两路径上的割点的数目 考虑到又是关于点双的题目, ...

  5. 「区间DP」「洛谷P1043」数字游戏

    「洛谷P1043」数字游戏 日后再写 代码 /*#!/bin/sh dir=$GEDIT_CURRENT_DOCUMENT_DIR name=$GEDIT_CURRENT_DOCUMENT_NAME ...

  6. 洛谷P1118 数字三角形游戏

    洛谷1118 数字三角形游戏 题目描述 有这么一个游戏: 写出一个1-N的排列a[i],然后每次将相邻两个数相加,构成新的序列,再对新序列进行这样的操作,显然每次构成的序列都比上一次的序列长度少1,直 ...

  7. 洛谷P1274-魔术数字游戏

    Problem 洛谷P1274-魔术数字游戏 Accept: 118    Submit: 243Time Limit: 1000 mSec    Memory Limit : 128MB Probl ...

  8. 洛谷P1288 取数游戏II(博弈)

    洛谷P1288 取数游戏II 先手必胜的条件需要满足如下中至少 \(1\) 条: 从初始位置向左走到第一个 \(0\) 的位置,经过边的数目为偶数(包含 \(0\) 这条边). 从初始位置向右走到第一 ...

  9. Solution -「JSOI 2019」「洛谷 P5334」节日庆典

    \(\mathscr{Description}\)   Link.   给定字符串 \(S\),求 \(S\) 的每个前缀的最小表示法起始下标(若有多个,取最小的).   \(|S|\le3\time ...

随机推荐

  1. 教你三步在CentOS 7 中安装或升级最新的内核

    转载自:https://www.linuxprobe.com/update-kernel-centos7.html #步骤 1:检查已安装的内核版本 >uname -sr #步骤 2:在 Cen ...

  2. Word2010制作个人名片

    原文链接: https://www.toutiao.com/i6488858441698771470/ 页面设置: 选择"页面布局"选项卡,"页面设置"功能组, ...

  3. 战争游戏(War Games 1983)剧情

    战争游戏 War Games(1983) 人工控制导弹发射 傍晚大雾,两值工作人员自驾一辆轿车到达监控俄罗斯核战争的防空基地,在门口出示工作证后进入基地,两工作人员和同事换班后,进入防空系统控制室开始 ...

  4. [转]浮点运算decimal.js

    开发过程中免不了有浮点运算,JavaScript浮点运算的精度问题会带来一些困扰 JavaScript 只有一种数字类型 ( Number ) JavaScript采用 IEEE 754 标准双精度浮 ...

  5. VirtualBox 安装 Ubuntu 20.04 全流程

    VirtualBox 安装 Ubuntu 20.04 全流程 内容概要 这个作业属于哪个课程 2022面向对象程序设计 这个作业要求在哪里 2022面向对象程序设计寒假作业1 这个作业的目标 在虚拟机 ...

  6. 带你玩转Flink流批一体分布式实时处理引擎

    摘要:Apache Flink是为分布式.高性能的流处理应用程序打造的开源流处理框架. 本文分享自华为云社区<[云驻共创]手把手教你玩转Flink流批一体分布式实时处理引擎>,作者: 萌兔 ...

  7. GIL全局解释器锁、死锁现象、python多线程的用处、进程池与线程池理论

    昨日内容回顾 僵尸进程与孤儿进程 # 僵尸进程: 所有的进程在运行结束之后并不会立刻销毁(父进程需要获取该进程的资源) # 孤儿进程: 子进程正常运行 但是产生该子进程的父进程意外死亡 # 守护进程: ...

  8. Gradle下载安装教程

    前言 1.gradle和maven一样都是用来构建java程序的,maven2004年开始兴起,gradle2012年开始诞生,既然已经有了maven这么成熟的构建工具为什么还有gradle的诞生呢, ...

  9. Linux身份鉴别机制原理

    传统的UNIX身份鉴别机制原理 传统的UNIX身份鉴别即口令认证方式,它主要通过识别用户的用户名或者UID号获取在/etc/shadow中存放的对应用户密码密文等信息,然后获取用户输入密码并采用cry ...

  10. python pyautogui

    使用pyautogui随机调用图库里的一张照片设置为壁纸,每天定时执行 代码 import time import pyautogui import random pyautogui.keyDown( ...