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的更多相关文章

  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. Object.keys(obj)--获取对象属性,该方法返回一个数组

    find: function(id){ var self = this; var _id = parseInt(id, 10), id = ''; Object.keys(self.data).for ...

  2. kotlin string

    Kotlin String split 操作实践   内容 此文章展示kotlin中对String字符串的split操作,如果你有遇到这方面的需求,希望对你有用. 1. split + 正则 先看下系 ...

  3. centos7升级内核

    载入elrepo源,搜索内核更新资源,并进行更新操作. 具体实验步骤: # 载入公钥rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org ...

  4. opencv 学习笔记

    Opencv 笔记 路径问题: 路径输入:Opencv载Qt中不能出现汉字,路径也不能出现汉字在vs中可以出现. (”D:/QTopencv/.1jpg”)=(”D:\\QTopencv\\.1jpg ...

  5. 05_ssm基础(一)之mybatis简单使用

    01.mybatis使用引导与准备 1.ssm框架 指: sping+springMVC+mybatis 2.学习mybatis前准备web标准项目结构 model中的Ticket代码如下: pack ...

  6. Java闰年的计算,Calendar的用法

    Java闰年的计算,Calendar的用法 代码如下: package com.aaa.zuoye; import java.text.ParseException; import java.util ...

  7. c# 项目的导入

    1.打开 2.手动添加现有项目,对照后找到未添加的空间,然后打开底层  选择 “#”文件打开即可 3.每个空间分别添加隐藏项  注意 bin与obj不需要添加 4.添加引用 5.可能需要删除   li ...

  8. as3.0加载swf并控制

    私人QQ 280841609 var myload:Loader=new Loader(); var url:URLRequest=new URLRequest("1.swf"); ...

  9. 合并两个排序的链表(python)

    题目描述 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则. # -*- coding:utf-8 -*- # class ListNode: # def _ ...

  10. 01背包 hdu1864

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1864 注意事项: 在这里所有输入的价格都是两位小数(题目没说,看论坛才知道的). 这里单项价格不能超过 ...