CF487E Tourists - Tarjan缩点 + 树剖 + multiset
Solution
先Tarjan求出点双联通分量 并缩点。 用$multiset$维护 点双内的最小点权。
容易发现, 点双内的最小点权必须包括与它相连的割边的点权。 所以我们必须想办法来维护。
所以考虑用割点的点权更新它的父节点, 这样查询 点双 内的最小点权只需要查询本身的 $multiset$ 和 它的父亲节点就可以了。
最后加个树剖就能过啦!
Code
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #include<set>
- #include<vector>
- #define rd read()
- using namespace std;
- const int N = 2e5 + ;
- const int inf = ~0U >> ;
- int Head[N << ], Tot;
- int head[N], tot;
- int low[N], dfn[N], cnt, col, c[N], nd_num, cut[N];
- int st[N], tp;
- int n, m, Q, a[N];
- int f[N << ], top[N << ], sz[N << ], son[N << ], mk, id[N << ], dep[N << ];
- vector<int> q[N];
- multiset<int> S[N << ];
- struct edge {
- int nxt, to;
- }e[N << ], E[N << ];
- int read() {
- int X = , p = ; char c = getchar();
- for (; c > '' || c < ''; c = getchar())
- if (c == '-') p = -;
- for (; c >= '' && c <= ''; c = getchar())
- X = X * + c - '';
- return X * p;
- }
- void add(int u, int v) {
- e[++tot].to = v;
- e[tot].nxt = head[u];
- head[u] = tot;
- }
- void Add(int u, int v) {
- E[++Tot].to = v;
- E[Tot].nxt = Head[u];
- Head[u] = Tot;
- }
- void tarjan(int u) {
- low[u] = dfn[u] = ++cnt;
- st[++tp] = u;
- int flag = ;
- for (int i = head[u]; i; i = e[i].nxt) {
- int nt = e[i].to;
- if (!dfn[nt]) {
- tarjan(nt);
- low[u] = min(low[u], low[nt]);
- if (low[nt] < dfn[u])
- continue;
- col++; flag++;
- cut[u] = ;
- for (; tp;) {
- int z = st[tp--];
- q[col].push_back(z);
- if (z == nt)
- break;
- }
- q[col].push_back(u);
- }
- else low[u] = min(low[u], dfn[nt]);
- }
- if (flag < && u == )
- cut[u] = ;
- }
- namespace SegT {
- int MIN[N << ];
- #define mid ((l + r) >> 1)
- #define lson nd << 1
- #define rson nd << 1 | 1
- void up(int nd) {
- MIN[nd] = min(MIN[lson], MIN[rson]);
- }
- void modify(int pos, int d, int l, int r, int nd) {
- if (l == r) {
- MIN[nd] = d;
- return;
- }
- if (pos <= mid)
- SegT::modify(pos, d, l, mid, lson);
- else
- SegT::modify(pos, d, mid + , r, rson);
- SegT::up(nd);
- }
- int query(int L, int R, int l, int r, int nd) {
- if (L <= l && r <= R)
- return MIN[nd];
- int tmp = inf;
- if(L <= mid)
- tmp = min(tmp, SegT::query(L, R, l, mid, lson));
- if(mid < R)
- tmp = min(tmp, SegT::query(L, R, mid + , r, rson));
- return tmp;
- }
- #undef mid
- #undef lson
- #undef rson
- }
- namespace SP {
- void dfs1(int u) {
- sz[u] = ;
- for (int i = Head[u]; i; i = E[i].nxt) {
- int nt = E[i].to;
- if (nt == f[u])
- continue;
- f[nt] = u;
- dep[nt] = dep[u] + ;
- SP::dfs1(nt);
- sz[u] += sz[nt];
- if(sz[nt] >= sz[son[u]])
- son[u] = nt;
- }
- }
- void dfs2(int u) {
- id[u] = ++mk;
- if (!son[u])
- return;
- top[son[u]] = top[u];
- SP::dfs2(son[u]);
- for (int i = Head[u]; i; i = E[i].nxt) {
- int nt = E[i].to;
- if (nt == f[u] || nt == son[u])
- continue;
- top[nt] = nt;
- SP::dfs2(nt);
- }
- }
- int query(int x, int y) {
- int re = inf, tmp;
- for (; top[x] != top[y];) {
- if (dep[top[x]] < dep[top[y]])
- swap(x, y);
- tmp = SegT::query(id[top[x]], id[x], , mk, );
- re = min(tmp, re);
- x = f[top[x]];
- }
- if (dep[x] < dep[y])
- swap(x, y);
- tmp = SegT::query(id[y], id[x], , mk, );
- re = min(tmp, re);
- if (f[y] && y <= col)
- tmp = SegT::query(id[f[y]], id[f[y]], , mk, );
- re = min(tmp, re);
- return re;
- }
- }
- int main()
- {
- n = rd; m = rd; Q = rd;
- for (int i = ; i <= n; ++i)
- a[i] = rd;
- for (int i = ; i <= m; ++i) {
- int u = rd, v = rd;
- add(u, v); add(v, u);
- }
- tarjan();
- nd_num = col;
- for (int i = ; i <= n; ++i)
- if (cut[i]) c[i] = ++nd_num;
- for (int i = ; i <= col; ++i)
- for (int j = , len = q[i].size(); j < len; ++j) {
- int x = q[i][j];
- if (cut[x])
- Add(c[x], i), Add(i, c[x]);
- else c[x] = i;
- }
- dep[] = ;
- SP::dfs1();
- top[] = ;
- SP::dfs2();
- for (int i = ; i <= n; ++i) {
- int x = c[i];
- S[x].insert(a[i]);
- if(x > col)
- S[f[x]].insert(a[i]);
- }
- for (int i = ; i <= nd_num; ++i) {
- int x = *S[i].begin();
- SegT::modify(id[i], x, , mk, );
- }
- for (; Q; Q--) {
- char ch = getchar();
- while (ch != 'A' && ch != 'C')
- ch = getchar();
- int u = rd, v = rd;
- if (ch == 'C') {
- swap(v, a[u]);
- S[c[u]].erase(S[c[u]].find(v));
- S[c[u]].insert(a[u]);
- int x = *S[c[u]].begin();
- SegT::modify(id[c[u]], x, , mk, );
- if (c[u] <= col)
- continue;
- S[f[c[u]]].erase(S[f[c[u]]].find(v));
- S[f[c[u]]].insert(a[u]);
- x = *S[f[c[u]]].begin();
- SegT::modify(id[f[c[u]]], x, , mk, );
- }
- else {
- if (u == v) printf("%d\n", a[u]);
- else printf("%d\n", SP::query(c[u], c[v]));
- }
- }
- }
CF487E Tourists - Tarjan缩点 + 树剖 + multiset的更多相关文章
- CF487E Tourists【圆方树+tarjan+multiset+树剖+线段树】
圆方树不仅能解决仙人掌问题(虽然我仙人掌问题也没用过圆方树都是瞎搞过去的),还可以解决一般图的问题 一般图问题在于缩完环不是一棵树,所以就缩点双(包括双向边) 每个方点存他所在点双内除根以外的点的最小 ...
- CF487E Tourists 【圆方树 + 树剖 + 堆】
题目链接 CF487E 题解 圆方树 + 树剖 裸题 建好圆方树维护路径上最小值即可 方点的值为其儿子的最小值,这个用堆维护 为什么只维护儿子?因为这样修改点的时候就只需要修改其父亲的堆 这样充分利用 ...
- CF487E Tourists(圆方树+堆+链剖)
本题解并不提供圆方树讲解. 所以不会圆方树的出门右转问yyb 没有修改的话圆方树+链剖. 方点的权值为点双连通分量里的最小值. 然后修改的话圆点照修,每一个方点维护一个小根堆. 考虑到可能被菊花卡死. ...
- poj3694 Network[边双缩点+树剖/并查集]
首先同一个点双内部的加边肯定不影响..所以先缩点成树,然后每次加一条边,这条对应的树上路径上所有边就都不是桥了,且每次操作独立作用,不相互影响(不过有可能本来一条边已经不是桥了又被标记了一次),所以每 ...
- cf1000E We Need More Bosses (tarjan缩点+树的直径)
题意:无向联通图,求一条最长的路径,路径长度定义为u到v必须经过的边的个数 如果把强联通分量都缩成一个点以后,每个点内部的边都是可替代的:而又因为这是个无向图,缩完点以后就是棵树,跑两遍dfs求直径即 ...
- F - Warm up HDU - 4612 tarjan缩点 + 树的直径 + 对tajan的再次理解
题目链接:https://vjudge.net/contest/67418#problem/F 题目大意:给你一个图,让你加一条边,使得原图中的桥尽可能的小.(谢谢梁学长的帮忙) 我对重边,tarja ...
- LUOGU P2416 泡芙 (缩点+树剖)
传送门 解题思路 首先先缩点,然后将缩完点的权值改成点中路径为1的条数,然后再将边权下放到点权上,求一个每个点到根的路径和,然后用树上2点距离公式算..刚开始写的线段树,T了2个点. #include ...
- HDU4612+Tarjan缩点+BFS求树的直径
tarjan+缩点+树的直径题意:给出n个点和m条边的图,存在重边,问加一条边以后,剩下的桥的数量最少为多少.先tarjan缩点,再在这棵树上求直径.加的边即是连接这条直径的两端. /* tarjan ...
- CF487E Tourists + 圆方树学习笔记(圆方树+树剖+线段树+multiset)
QWQ果然我已经什么都学不会的人了. 这个题目要求的是图上所有路径的点权和!QWQ(我只会树上啊!) 这个如果是好啊 这时候就需要 圆方树! 首先在介绍圆方树之前,我们先来一点简单的前置知识 首先,我 ...
随机推荐
- opencv矩阵操作
1.初始化矩阵: 方式一.逐点赋值式: CvMat* mat = cvCreateMat( 2, 2, CV_64FC1 ); cvZero( mat ); cvmSet( mat, 0, 0, 1 ...
- android Zxing 扫描区域的大小设置和自定义扫描view
自己的项目中,只需要修改: CameraManager 里面的 MAX_FRAME_WIDTH .MAX_FRAME_HEIGHT 的值 private static final int MIN_FR ...
- 使用Js控制ReactRouter路由
[使用Js控制ReactRouter路由] 首先引入PropTypes: const PropTypes = require('prop-types'); 然后定义context的router属性: ...
- scrapy 异步存储mysql
1.在setting中设置MySQL连接信息 HOST='101.201.70.139'MYSQL_DBNAME='anttest'MYSQL_PASSWORD='Myjr678!@#'MYSQL_U ...
- Redis集群架构【转载】
Redis 集群的 TCP 端口(Redis Cluster TCP ports) 每个 Redis 集群节点需要两个 TCP 连接打开.正常的 TCP 端口用来服务客户端,例如 6379,加 100 ...
- 纯css3棋盘图案背景以及45度斜纹背景
css代码 .stripes { height: 250px; width: 375px; float: left; margin: 10px; ...
- vue element upload上传、清除等
如果项目中可以使用file-list,那我们可以点击file-list删除文件列表: 有时候项目中是不要这个文件列表的,所以在上传成功以后,文件列表一直存在,要重新上传就必须刷新页面,所以我们需要手动 ...
- 从尾到头打印链表(python)
题目描述 输入一个链表,按链表值从尾到头的顺序返回一个ArrayList. # -*- coding:utf-8 -*- # class ListNode: # def __init__(self, ...
- poj1256(贪心+并查集)
题目链接:http://poj.org/problem?id=1456 题意:给n件商品的价格和卖出截至时间,每一个单位时间最多只能卖出一件商品,求能获得的最大利润. 思路:首先是贪心,为获得最大利润 ...
- PHP文件上传与下载
一:上传文件与报错 $_FILES 超全局数组,包含了有关上传文件的所有信息! 而且,这个数组中只包含文件相关信息,其他数据依然在$_POST里面$_FILES是一个二维数组,每上传一个文件,都是数组 ...