Solution

先Tarjan求出点双联通分量 并缩点。 用$multiset$维护 点双内的最小点权。

容易发现, 点双内的最小点权必须包括与它相连的割边的点权。 所以我们必须想办法来维护。

所以考虑用割点的点权更新它的父节点, 这样查询 点双 内的最小点权只需要查询本身的 $multiset$ 和 它的父亲节点就可以了。

最后加个树剖就能过啦!

Code

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<set>
  5. #include<vector>
  6. #define rd read()
  7. using namespace std;
  8.  
  9. const int N = 2e5 + ;
  10. const int inf = ~0U >> ;
  11.  
  12. int Head[N << ], Tot;
  13. int head[N], tot;
  14. int low[N], dfn[N], cnt, col, c[N], nd_num, cut[N];
  15. int st[N], tp;
  16. int n, m, Q, a[N];
  17. int f[N << ], top[N << ], sz[N << ], son[N << ], mk, id[N << ], dep[N << ];
  18.  
  19. vector<int> q[N];
  20. multiset<int> S[N << ];
  21.  
  22. struct edge {
  23. int nxt, to;
  24. }e[N << ], E[N << ];
  25.  
  26. int read() {
  27. int X = , p = ; char c = getchar();
  28. for (; c > '' || c < ''; c = getchar())
  29. if (c == '-') p = -;
  30. for (; c >= '' && c <= ''; c = getchar())
  31. X = X * + c - '';
  32. return X * p;
  33. }
  34.  
  35. void add(int u, int v) {
  36. e[++tot].to = v;
  37. e[tot].nxt = head[u];
  38. head[u] = tot;
  39. }
  40.  
  41. void Add(int u, int v) {
  42. E[++Tot].to = v;
  43. E[Tot].nxt = Head[u];
  44. Head[u] = Tot;
  45. }
  46.  
  47. void tarjan(int u) {
  48. low[u] = dfn[u] = ++cnt;
  49. st[++tp] = u;
  50. int flag = ;
  51. for (int i = head[u]; i; i = e[i].nxt) {
  52. int nt = e[i].to;
  53. if (!dfn[nt]) {
  54. tarjan(nt);
  55. low[u] = min(low[u], low[nt]);
  56. if (low[nt] < dfn[u])
  57. continue;
  58. col++; flag++;
  59. cut[u] = ;
  60. for (; tp;) {
  61. int z = st[tp--];
  62. q[col].push_back(z);
  63. if (z == nt)
  64. break;
  65. }
  66. q[col].push_back(u);
  67. }
  68. else low[u] = min(low[u], dfn[nt]);
  69. }
  70. if (flag < && u == )
  71. cut[u] = ;
  72. }
  73.  
  74. namespace SegT {
  75.  
  76. int MIN[N << ];
  77.  
  78. #define mid ((l + r) >> 1)
  79. #define lson nd << 1
  80. #define rson nd << 1 | 1
  81.  
  82. void up(int nd) {
  83. MIN[nd] = min(MIN[lson], MIN[rson]);
  84. }
  85.  
  86. void modify(int pos, int d, int l, int r, int nd) {
  87. if (l == r) {
  88. MIN[nd] = d;
  89. return;
  90. }
  91. if (pos <= mid)
  92. SegT::modify(pos, d, l, mid, lson);
  93. else
  94. SegT::modify(pos, d, mid + , r, rson);
  95. SegT::up(nd);
  96. }
  97. int query(int L, int R, int l, int r, int nd) {
  98. if (L <= l && r <= R)
  99. return MIN[nd];
  100. int tmp = inf;
  101. if(L <= mid)
  102. tmp = min(tmp, SegT::query(L, R, l, mid, lson));
  103. if(mid < R)
  104. tmp = min(tmp, SegT::query(L, R, mid + , r, rson));
  105. return tmp;
  106. }
  107.  
  108. #undef mid
  109. #undef lson
  110. #undef rson
  111. }
  112.  
  113. namespace SP {
  114.  
  115. void dfs1(int u) {
  116. sz[u] = ;
  117. for (int i = Head[u]; i; i = E[i].nxt) {
  118. int nt = E[i].to;
  119. if (nt == f[u])
  120. continue;
  121. f[nt] = u;
  122. dep[nt] = dep[u] + ;
  123. SP::dfs1(nt);
  124. sz[u] += sz[nt];
  125. if(sz[nt] >= sz[son[u]])
  126. son[u] = nt;
  127. }
  128. }
  129.  
  130. void dfs2(int u) {
  131. id[u] = ++mk;
  132. if (!son[u])
  133. return;
  134. top[son[u]] = top[u];
  135. SP::dfs2(son[u]);
  136. for (int i = Head[u]; i; i = E[i].nxt) {
  137. int nt = E[i].to;
  138. if (nt == f[u] || nt == son[u])
  139. continue;
  140. top[nt] = nt;
  141. SP::dfs2(nt);
  142. }
  143. }
  144.  
  145. int query(int x, int y) {
  146. int re = inf, tmp;
  147. for (; top[x] != top[y];) {
  148. if (dep[top[x]] < dep[top[y]])
  149. swap(x, y);
  150. tmp = SegT::query(id[top[x]], id[x], , mk, );
  151. re = min(tmp, re);
  152. x = f[top[x]];
  153. }
  154. if (dep[x] < dep[y])
  155. swap(x, y);
  156. tmp = SegT::query(id[y], id[x], , mk, );
  157. re = min(tmp, re);
  158. if (f[y] && y <= col)
  159. tmp = SegT::query(id[f[y]], id[f[y]], , mk, );
  160. re = min(tmp, re);
  161. return re;
  162. }
  163. }
  164.  
  165. int main()
  166. {
  167. n = rd; m = rd; Q = rd;
  168. for (int i = ; i <= n; ++i)
  169. a[i] = rd;
  170. for (int i = ; i <= m; ++i) {
  171. int u = rd, v = rd;
  172. add(u, v); add(v, u);
  173. }
  174. tarjan();
  175. nd_num = col;
  176. for (int i = ; i <= n; ++i)
  177. if (cut[i]) c[i] = ++nd_num;
  178. for (int i = ; i <= col; ++i)
  179. for (int j = , len = q[i].size(); j < len; ++j) {
  180. int x = q[i][j];
  181. if (cut[x])
  182. Add(c[x], i), Add(i, c[x]);
  183. else c[x] = i;
  184. }
  185. dep[] = ;
  186. SP::dfs1();
  187. top[] = ;
  188. SP::dfs2();
  189. for (int i = ; i <= n; ++i) {
  190. int x = c[i];
  191. S[x].insert(a[i]);
  192. if(x > col)
  193. S[f[x]].insert(a[i]);
  194. }
  195. for (int i = ; i <= nd_num; ++i) {
  196. int x = *S[i].begin();
  197. SegT::modify(id[i], x, , mk, );
  198. }
  199. for (; Q; Q--) {
  200. char ch = getchar();
  201. while (ch != 'A' && ch != 'C')
  202. ch = getchar();
  203. int u = rd, v = rd;
  204. if (ch == 'C') {
  205. swap(v, a[u]);
  206. S[c[u]].erase(S[c[u]].find(v));
  207. S[c[u]].insert(a[u]);
  208. int x = *S[c[u]].begin();
  209. SegT::modify(id[c[u]], x, , mk, );
  210. if (c[u] <= col)
  211. continue;
  212. S[f[c[u]]].erase(S[f[c[u]]].find(v));
  213. S[f[c[u]]].insert(a[u]);
  214. x = *S[f[c[u]]].begin();
  215. SegT::modify(id[f[c[u]]], x, , mk, );
  216. }
  217. else {
  218. if (u == v) printf("%d\n", a[u]);
  219. else printf("%d\n", SP::query(c[u], c[v]));
  220. }
  221. }
  222. }

CF487E Tourists - Tarjan缩点 + 树剖 + multiset的更多相关文章

  1. CF487E Tourists【圆方树+tarjan+multiset+树剖+线段树】

    圆方树不仅能解决仙人掌问题(虽然我仙人掌问题也没用过圆方树都是瞎搞过去的),还可以解决一般图的问题 一般图问题在于缩完环不是一棵树,所以就缩点双(包括双向边) 每个方点存他所在点双内除根以外的点的最小 ...

  2. CF487E Tourists 【圆方树 + 树剖 + 堆】

    题目链接 CF487E 题解 圆方树 + 树剖 裸题 建好圆方树维护路径上最小值即可 方点的值为其儿子的最小值,这个用堆维护 为什么只维护儿子?因为这样修改点的时候就只需要修改其父亲的堆 这样充分利用 ...

  3. CF487E Tourists(圆方树+堆+链剖)

    本题解并不提供圆方树讲解. 所以不会圆方树的出门右转问yyb 没有修改的话圆方树+链剖. 方点的权值为点双连通分量里的最小值. 然后修改的话圆点照修,每一个方点维护一个小根堆. 考虑到可能被菊花卡死. ...

  4. poj3694 Network[边双缩点+树剖/并查集]

    首先同一个点双内部的加边肯定不影响..所以先缩点成树,然后每次加一条边,这条对应的树上路径上所有边就都不是桥了,且每次操作独立作用,不相互影响(不过有可能本来一条边已经不是桥了又被标记了一次),所以每 ...

  5. cf1000E We Need More Bosses (tarjan缩点+树的直径)

    题意:无向联通图,求一条最长的路径,路径长度定义为u到v必须经过的边的个数 如果把强联通分量都缩成一个点以后,每个点内部的边都是可替代的:而又因为这是个无向图,缩完点以后就是棵树,跑两遍dfs求直径即 ...

  6. F - Warm up HDU - 4612 tarjan缩点 + 树的直径 + 对tajan的再次理解

    题目链接:https://vjudge.net/contest/67418#problem/F 题目大意:给你一个图,让你加一条边,使得原图中的桥尽可能的小.(谢谢梁学长的帮忙) 我对重边,tarja ...

  7. LUOGU P2416 泡芙 (缩点+树剖)

    传送门 解题思路 首先先缩点,然后将缩完点的权值改成点中路径为1的条数,然后再将边权下放到点权上,求一个每个点到根的路径和,然后用树上2点距离公式算..刚开始写的线段树,T了2个点. #include ...

  8. HDU4612+Tarjan缩点+BFS求树的直径

    tarjan+缩点+树的直径题意:给出n个点和m条边的图,存在重边,问加一条边以后,剩下的桥的数量最少为多少.先tarjan缩点,再在这棵树上求直径.加的边即是连接这条直径的两端. /* tarjan ...

  9. CF487E Tourists + 圆方树学习笔记(圆方树+树剖+线段树+multiset)

    QWQ果然我已经什么都学不会的人了. 这个题目要求的是图上所有路径的点权和!QWQ(我只会树上啊!) 这个如果是好啊 这时候就需要 圆方树! 首先在介绍圆方树之前,我们先来一点简单的前置知识 首先,我 ...

随机推荐

  1. opencv矩阵操作

    1.初始化矩阵: 方式一.逐点赋值式: CvMat* mat = cvCreateMat( 2, 2, CV_64FC1 ); cvZero( mat ); cvmSet( mat, 0, 0, 1 ...

  2. android Zxing 扫描区域的大小设置和自定义扫描view

    自己的项目中,只需要修改: CameraManager 里面的 MAX_FRAME_WIDTH .MAX_FRAME_HEIGHT 的值 private static final int MIN_FR ...

  3. 使用Js控制ReactRouter路由

    [使用Js控制ReactRouter路由] 首先引入PropTypes: const PropTypes = require('prop-types'); 然后定义context的router属性: ...

  4. scrapy 异步存储mysql

    1.在setting中设置MySQL连接信息 HOST='101.201.70.139'MYSQL_DBNAME='anttest'MYSQL_PASSWORD='Myjr678!@#'MYSQL_U ...

  5. Redis集群架构【转载】

    Redis 集群的 TCP 端口(Redis Cluster TCP ports) 每个 Redis 集群节点需要两个 TCP 连接打开.正常的 TCP 端口用来服务客户端,例如 6379,加 100 ...

  6. 纯css3棋盘图案背景以及45度斜纹背景

    css代码  .stripes {     height: 250px;     width: 375px;     float: left;          margin: 10px;      ...

  7. vue element upload上传、清除等

    如果项目中可以使用file-list,那我们可以点击file-list删除文件列表: 有时候项目中是不要这个文件列表的,所以在上传成功以后,文件列表一直存在,要重新上传就必须刷新页面,所以我们需要手动 ...

  8. 从尾到头打印链表(python)

    题目描述 输入一个链表,按链表值从尾到头的顺序返回一个ArrayList. # -*- coding:utf-8 -*- # class ListNode: # def __init__(self, ...

  9. poj1256(贪心+并查集)

    题目链接:http://poj.org/problem?id=1456 题意:给n件商品的价格和卖出截至时间,每一个单位时间最多只能卖出一件商品,求能获得的最大利润. 思路:首先是贪心,为获得最大利润 ...

  10. PHP文件上传与下载

    一:上传文件与报错 $_FILES 超全局数组,包含了有关上传文件的所有信息! 而且,这个数组中只包含文件相关信息,其他数据依然在$_POST里面$_FILES是一个二维数组,每上传一个文件,都是数组 ...