\(\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}\)

#include <queue>
#include <cstdio> #define adj( g, u, v ) \
for ( int eid = g.head[u], v; v = g.to[eid], eid; eid = g.nxt[eid] ) const int MAXN = 2e5, MAXM = 4e5;
int n, m, q, val[MAXN + 5], snode;
int dfc, tp, dfn[MAXN + 5], low[MAXN + 5], stk[MAXN + 5];
int siz[MAXN + 5], dep[MAXN + 5], fa[MAXN + 5], son[MAXN + 5];
int top[MAXN + 5]; inline bool chkmin ( int& a, const int b ) { return b < a ? a = b, true : false; } struct Graph {
int ecnt, head[MAXN + 5], to[MAXM + 5], nxt[MAXM + 5];
inline void link ( const int s, const int t ) {
to[++ ecnt] = t, nxt[ecnt] = head[s];
head[s] = ecnt;
}
inline void add ( const int u, const int v ) {
link ( u, v ), link ( v, u );
}
} src, tre; struct Heap {
std::priority_queue<int, std::vector<int>, std::greater<int> > val, rem;
inline void push ( const int ele ) { val.push ( ele ); }
inline void pop ( const int ele ) { rem.push ( ele ); }
inline int top () {
for ( ; ! val.empty () && ! rem.empty () && val.top () == rem.top (); val.pop (), rem.pop () );
return val.empty () ? -1 : val.top ();
}
} heap[MAXN * 2 + 5]; struct SegmentTree {
int mn[MAXN << 3];
inline void pushup ( const int rt ) { chkmin ( mn[rt] = mn[rt << 1], mn[rt << 1 | 1] ); }
inline void update ( const int rt, const int l, const int r, const int x, const int v ) {
if ( l == r ) return void ( mn[rt] = v );
int mid = l + r >> 1;
if ( x <= mid ) update ( rt << 1, l, mid, x, v );
else update ( rt << 1 | 1, mid + 1, r, x, v );
pushup ( rt );
}
inline int query ( const int rt, const int l, const int r, const int ql, const int qr ) {
if ( ql <= l && r <= qr ) return mn[rt];
int ret = 2e9, mid = l + r >> 1;
if ( ql <= mid ) chkmin ( ret, query ( rt << 1, l, mid, ql, qr ) );
if ( mid < qr ) chkmin ( ret, query ( rt << 1 | 1, mid + 1, r, ql, qr ) );
return ret;
}
} st; inline void Tarjan ( const int u, const int f ) {
dfn[u] = low[u] = ++ dfc, stk[++ tp] = u;
adj ( src, u, v ) if ( v ^ f ) {
if ( ! dfn[v] ) {
Tarjan ( v, u ), chkmin ( low[u], low[v] );
if ( low[v] >= dfn[u] ) {
tre.add ( u, ++ snode );
do {
tre.add ( snode, stk[tp] );
heap[snode].push ( val[stk[tp]] );
} while ( stk[tp --] ^ v );
}
} else chkmin ( low[u], dfn[v] );
}
} inline void DFS1 ( const int u, const int f ) {
dep[u] = dep[fa[u] = f] + 1, siz[u] = 1;
adj ( tre, u, v ) if ( v ^ f ) {
DFS1 ( v, u ), siz[u] += siz[v];
if ( siz[v] > siz[son[u]] ) son[u] = v;
}
} inline void DFS2 ( const int u, const int tp ) {
top[u] = tp, dfn[u] = ++ dfc;
if ( son[u] ) DFS2 ( son[u], tp );
adj ( tre, u, v ) if ( v ^ fa[u] && v ^ son[u] ) DFS2 ( v, v );
} inline int queryChain ( int u, int v ) {
int ret = 2e9;
while ( top[u] ^ top[v] ) {
if ( dep[top[u]] < dep[top[v]] ) u ^= v ^= u ^= v;
chkmin ( ret, st.query ( 1, 1, snode, dfn[top[u]], dfn[u] ) );
u = fa[top[u]];
}
if ( dep[u] < dep[v] ) u ^= v ^= u ^= v;
chkmin ( ret, st.query ( 1, 1, snode, dfn[v], dfn[u] ) );
if ( v > n && fa[v] ) chkmin ( ret, val[fa[v]] );
return ret;
} int main () {
scanf ( "%d %d %d", &n, &m, &q ), snode = n;
for ( int i = 1; i <= n; ++ i ) scanf ( "%d", &val[i] );
for ( int i = 1, u, v; i <= m; ++ i ) {
scanf ( "%d %d", &u, &v );
src.add ( u, v );
}
Tarjan ( 1, 0 ), dfc = 0;
DFS1 ( 1, 0 ), DFS2 ( 1, 1 );
for ( int i = 1; i <= n; ++ i ) st.update ( 1, 1, snode, dfn[i], val[i] );
for ( int i = n + 1; i <= snode; ++ i ) st.update ( 1, 1, snode, dfn[i], heap[i].top () );
char op[5]; int a, b;
for ( ; q --; ) {
scanf ( "%s %d %d", op, &a, &b );
if ( op[0] == 'C' ) {
st.update ( 1, 1, snode, dfn[a], b );
if ( fa[a] ) {
heap[fa[a]].pop ( val[a] );
heap[fa[a]].push ( b );
st.update ( 1, 1, snode, dfn[fa[a]], heap[fa[a]].top () );
}
val[a] = b;
} else {
printf ( "%d\n", queryChain ( a, b ) );
}
}
return 0;
}

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. 查询Oracle数据库的字符集

    How do you check the Oracle database character set? SQL> select value from nls_database_parameter ...

  2. Docker 容器化的 SonarQube 服务在不同主机之间的迁移

    安装 docker-ce // https://docs.docker.com/install/linux/docker-ce/centos/ $ sudo yum remove docker \ d ...

  3. 嵌入式学习第四步—C语言学习用软件安装

    学习一门计算机语言,不能光靠看书,最主要的是要动手联系.不记得从哪里看到过,要成为一名网络大牛,要有10万行以上的程序才是基础. 首先需要一个能够编辑程序的地方(IDE),经过大约10天的网上看各种视 ...

  4. Android官方文档翻译 十八 4.2Pausing and Resuming an Activity

    Pausing and Resuming an Activity 暂停和恢复一个activity This lesson teaches you to 这节课教给你 Pause Your Activi ...

  5. 《剑指offer》面试题17. 打印从1到最大的n位数

    问题描述 输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数.比如输入 3,则打印出 1.2.3 一直到最大的 3 位数 999. 示例 1: 输入: n = 1 输出: [1,2,3,4,5 ...

  6. winform创建桌面快捷方式

    //引用IWshRuntimeLibrary COM组件-Windows Script Host Object Model /// <summary> /// 创建快捷方式的类 /// & ...

  7. 【体验】在Adobe After Effects CC 2018中使用脚本创建窗口

    1.主界面 2.脚本编辑器主界面 3.对象浏览器 在脚本编辑器中按F1 4.写一段 ScriptUI var win = new Window('window', 'my win', [100, 10 ...

  8. gin中绑定html复选框

    main.go package main import "github.com/gin-gonic/gin" type myForm struct { Colors []strin ...

  9. web下载文件的头消息

    resp.setHeader("Content-disposition","attachment;filename="+filename);

  10. linux系统——Redis集群搭建(主从+哨兵模式)

    趁着这几天刚好有点空,就来写一下redis的集群搭建,我跟大家先说明,本文的redis集群因为linux服务器只是阿里云一台服务器,所以集群是redis启动不同端口,但是也能达到集群的要求.其实不同服 ...