\(\mathcal{Description}\)

  Link.

  维护一个 \(n\) 个点 \(m\) 条边的简单无向连通图,点有点权。\(q\) 次操作:

  • 修改单点点权。
  • 询问两点所有可能路径上点权的最小值。

  \(n,m,q\le10^5\)。

\(\mathcal{Solution}\)

  怎么可能维护图嘛,肯定是维护圆方树咯!

  一个比较 naive 的想法是,每个方点维护其邻接圆点的最小值,树链剖分处理询问。

  不过修改的复杂度会由于菊花退化:修改”花蕊“的圆点,四周 \(\mathcal O(n)\) 个方点的信息都需要修改。

  联想到 array 这道题,我们尝试”弱化“方点所维护的信息。每个方点,维护其圆方树上儿子们的点权最小值。那么每次修改圆点,至多就只有其父亲需要修改信息了。

  于是,每个方点用 std::multiset 或者常见的双堆 trick 维护最小值信息(推荐后者,常数较小),再用一样的树剖处理询问即可。

  复杂度 \(\mathcal O(n\log^2n)\)。

\(\mathcal{Code}\)

  1. #include <queue>
  2. #include <cstdio>
  3. #define adj( g, u, v ) \
  4. for ( int eid = g.head[u], v; v = g.to[eid], eid; eid = g.nxt[eid] )
  5. const int MAXN = 2e5, MAXM = 4e5;
  6. int n, m, q, val[MAXN + 5], snode;
  7. int dfc, tp, dfn[MAXN + 5], low[MAXN + 5], stk[MAXN + 5];
  8. int siz[MAXN + 5], dep[MAXN + 5], fa[MAXN + 5], son[MAXN + 5];
  9. int top[MAXN + 5];
  10. inline bool chkmin ( int& a, const int b ) { return b < a ? a = b, true : false; }
  11. struct Graph {
  12. int ecnt, head[MAXN + 5], to[MAXM + 5], nxt[MAXM + 5];
  13. inline void link ( const int s, const int t ) {
  14. to[++ ecnt] = t, nxt[ecnt] = head[s];
  15. head[s] = ecnt;
  16. }
  17. inline void add ( const int u, const int v ) {
  18. link ( u, v ), link ( v, u );
  19. }
  20. } src, tre;
  21. struct Heap {
  22. std::priority_queue<int, std::vector<int>, std::greater<int> > val, rem;
  23. inline void push ( const int ele ) { val.push ( ele ); }
  24. inline void pop ( const int ele ) { rem.push ( ele ); }
  25. inline int top () {
  26. for ( ; ! val.empty () && ! rem.empty () && val.top () == rem.top (); val.pop (), rem.pop () );
  27. return val.empty () ? -1 : val.top ();
  28. }
  29. } heap[MAXN * 2 + 5];
  30. struct SegmentTree {
  31. int mn[MAXN << 3];
  32. inline void pushup ( const int rt ) { chkmin ( mn[rt] = mn[rt << 1], mn[rt << 1 | 1] ); }
  33. inline void update ( const int rt, const int l, const int r, const int x, const int v ) {
  34. if ( l == r ) return void ( mn[rt] = v );
  35. int mid = l + r >> 1;
  36. if ( x <= mid ) update ( rt << 1, l, mid, x, v );
  37. else update ( rt << 1 | 1, mid + 1, r, x, v );
  38. pushup ( rt );
  39. }
  40. inline int query ( const int rt, const int l, const int r, const int ql, const int qr ) {
  41. if ( ql <= l && r <= qr ) return mn[rt];
  42. int ret = 2e9, mid = l + r >> 1;
  43. if ( ql <= mid ) chkmin ( ret, query ( rt << 1, l, mid, ql, qr ) );
  44. if ( mid < qr ) chkmin ( ret, query ( rt << 1 | 1, mid + 1, r, ql, qr ) );
  45. return ret;
  46. }
  47. } st;
  48. inline void Tarjan ( const int u, const int f ) {
  49. dfn[u] = low[u] = ++ dfc, stk[++ tp] = u;
  50. adj ( src, u, v ) if ( v ^ f ) {
  51. if ( ! dfn[v] ) {
  52. Tarjan ( v, u ), chkmin ( low[u], low[v] );
  53. if ( low[v] >= dfn[u] ) {
  54. tre.add ( u, ++ snode );
  55. do {
  56. tre.add ( snode, stk[tp] );
  57. heap[snode].push ( val[stk[tp]] );
  58. } while ( stk[tp --] ^ v );
  59. }
  60. } else chkmin ( low[u], dfn[v] );
  61. }
  62. }
  63. inline void DFS1 ( const int u, const int f ) {
  64. dep[u] = dep[fa[u] = f] + 1, siz[u] = 1;
  65. adj ( tre, u, v ) if ( v ^ f ) {
  66. DFS1 ( v, u ), siz[u] += siz[v];
  67. if ( siz[v] > siz[son[u]] ) son[u] = v;
  68. }
  69. }
  70. inline void DFS2 ( const int u, const int tp ) {
  71. top[u] = tp, dfn[u] = ++ dfc;
  72. if ( son[u] ) DFS2 ( son[u], tp );
  73. adj ( tre, u, v ) if ( v ^ fa[u] && v ^ son[u] ) DFS2 ( v, v );
  74. }
  75. inline int queryChain ( int u, int v ) {
  76. int ret = 2e9;
  77. while ( top[u] ^ top[v] ) {
  78. if ( dep[top[u]] < dep[top[v]] ) u ^= v ^= u ^= v;
  79. chkmin ( ret, st.query ( 1, 1, snode, dfn[top[u]], dfn[u] ) );
  80. u = fa[top[u]];
  81. }
  82. if ( dep[u] < dep[v] ) u ^= v ^= u ^= v;
  83. chkmin ( ret, st.query ( 1, 1, snode, dfn[v], dfn[u] ) );
  84. if ( v > n && fa[v] ) chkmin ( ret, val[fa[v]] );
  85. return ret;
  86. }
  87. int main () {
  88. scanf ( "%d %d %d", &n, &m, &q ), snode = n;
  89. for ( int i = 1; i <= n; ++ i ) scanf ( "%d", &val[i] );
  90. for ( int i = 1, u, v; i <= m; ++ i ) {
  91. scanf ( "%d %d", &u, &v );
  92. src.add ( u, v );
  93. }
  94. Tarjan ( 1, 0 ), dfc = 0;
  95. DFS1 ( 1, 0 ), DFS2 ( 1, 1 );
  96. for ( int i = 1; i <= n; ++ i ) st.update ( 1, 1, snode, dfn[i], val[i] );
  97. for ( int i = n + 1; i <= snode; ++ i ) st.update ( 1, 1, snode, dfn[i], heap[i].top () );
  98. char op[5]; int a, b;
  99. for ( ; q --; ) {
  100. scanf ( "%s %d %d", op, &a, &b );
  101. if ( op[0] == 'C' ) {
  102. st.update ( 1, 1, snode, dfn[a], b );
  103. if ( fa[a] ) {
  104. heap[fa[a]].pop ( val[a] );
  105. heap[fa[a]].push ( b );
  106. st.update ( 1, 1, snode, dfn[fa[a]], heap[fa[a]].top () );
  107. }
  108. val[a] = b;
  109. } else {
  110. printf ( "%d\n", queryChain ( a, b ) );
  111. }
  112. }
  113. return 0;
  114. }

Solution -「CF 487E」Tourists的更多相关文章

  1. Solution -「CF 1342E」Placing Rooks

    \(\mathcal{Description}\)   Link.   在一个 \(n\times n\) 的国际象棋棋盘上摆 \(n\) 个车,求满足: 所有格子都可以被攻击到. 恰好存在 \(k\ ...

  2. Solution -「CF 1622F」Quadratic Set

    \(\mathscr{Description}\)   Link.   求 \(S\subseteq\{1,2,\dots,n\}\),使得 \(\prod_{i\in S}i\) 是完全平方数,并最 ...

  3. Solution -「CF 923F」Public Service

    \(\mathscr{Description}\)   Link.   给定两棵含 \(n\) 个结点的树 \(T_1=(V_1,E_1),T_2=(V_2,E_2)\),求一个双射 \(\varph ...

  4. Solution -「CF 923E」Perpetual Subtraction

    \(\mathcal{Description}\)   Link.   有一个整数 \(x\in[0,n]\),初始时以 \(p_i\) 的概率取值 \(i\).进行 \(m\) 轮变换,每次均匀随机 ...

  5. Solution -「CF 1586F」Defender of Childhood Dreams

    \(\mathcal{Description}\)   Link.   定义有向图 \(G=(V,E)\),\(|V|=n\),\(\lang u,v\rang \in E \Leftrightarr ...

  6. Solution -「CF 1237E」Balanced Binary Search Trees

    \(\mathcal{Description}\)   Link.   定义棵点权为 \(1\sim n\) 的二叉搜索树 \(T\) 是 好树,当且仅当: 除去最深的所有叶子后,\(T\) 是满的: ...

  7. Solution -「CF 623E」Transforming Sequence

    题目 题意简述   link.   有一个 \(n\) 个元素的集合,你需要进行 \(m\) 次操作.每次操作选择集合的一个非空子集,要求该集合不是已选集合的并的子集.求操作的方案数,对 \(10^9 ...

  8. Solution -「CF 1023F」Mobile Phone Network

    \(\mathcal{Description}\)   Link.   有一个 \(n\) 个结点的图,并给定 \(m_1\) 条无向带权黑边,\(m_2\) 条无向无权白边.你需要为每条白边指定边权 ...

  9. Solution -「CF 599E」Sandy and Nuts

    \(\mathcal{Description}\)   Link.   指定一棵大小为 \(n\),以 \(1\) 为根的有根树的 \(m\) 对邻接关系与 \(q\) 组 \(\text{LCA}\ ...

随机推荐

  1. go 使用 sort 对切片进行排序

    golang对slice的排序 golang里面需要使用sort包,并且实现几个接口Len, Swap, Less sort 包排序demo 假如现在有个slice 叫做 ids 里面保存的数据类型是 ...

  2. Go语言系列之time

    time包是go语言的内置库,提供了时间的显示和测量用的函数.日历的计算采用的是公历. 一.时间类型 time.Time类型表示时间.我们可以通过time.Now()函数获取当前的时间对象,然后获取时 ...

  3. 万级K8s集群背后 etcd 稳定性及性能优化实践

    1背景与挑战随着腾讯自研上云及公有云用户的迅速增长,一方面,腾讯云容器服务TKE服务数量和核数大幅增长, 另一方面我们提供的容器服务类型(TKE托管及独立集群.EKS弹性集群.edge边缘计算集群.m ...

  4. Centos下安装Maven私服Nexus

    dockers安装Nexus,指定访问路径(默认为/:在使用Nginx做反向代理时,最好指定访问路径),并在容器外持久化数据,避免Nexus容器升级后数据丢失. 安装并启动 docker run -d ...

  5. Java中:接口,抽象类,内部类

    Java8中的接口 public interface Output { //接口里定义的成员变量只能是常量 //默认使用public static final修饰 int MAX_CACHE_LINE ...

  6. pytest文档6-allure-pytest

    allure-pytest 环境准备 windows环境相关: python 3.6版本pytest 4.5.0版本allure-pytest 2.8.6 最新版 使用pip安装pytest和allu ...

  7. golang中往脚本传递参数的两种用法os.Args和flag

    1. os.Args package main import ( "fmt" "os" ) func main() { // 执行:./demo.exe 127 ...

  8. StringBuilder类介绍

    1 package cn.itcast.p2.stringbuffer.demo; 2 3 public class StringBuilderDemo { 4 public static void ...

  9. IoC容器-Bean管理注解方式(创建对象)

    IoC操作Bean管理(基于注解方式) 1,什么是注解 (1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值,属性名称=属性值...) (2)使用注解,注解作用在类上面,方法上面,属性上面 ( ...

  10. MySQL更新数据时,日志(redo log、binlog)执行流程

    1:背景 项目需要做Es和数据库的同步,而手动在代码中进行数据同步又是Es的一些不必要的数据同步操作和业务逻辑耦合,所以使用的了读取mysql的binlog日志的方式进行同步Es的数据. 问题1:根据 ...