E. Tourists

题意:

无向连通图

  • C a w: 表示 a 城市的纪念品售价变成 w。
  • A a b: 表示有一个游客要从 a 城市到 b 城市,你要回答在所有他的旅行路径中最低售价的最低可能值。

\(1≤n,m,q≤10^5,1≤w_i\le10^9\)


显然一个点双连通分量中想去任何点都是可以的。

那么bcc缩点,树剖一下就好了?

割点可以存在于多个bcc!

所以把割点单独拿出来,向每个bcc连边


修改割点的权值怎么办?

每个割点的信息合并到父亲bcc里,查询的时候lca为bcc那么额外加上父亲割点的信息就行了


同一个bcc以及孩子割点还要用个multiset维护才能字词修改...


然后吐槽一下bcc,行为真的很奇怪啊,甚至\(u—v\)这样的东西都会当做一个bcc...

写+调了4个多小时…6.5kb...到半夜12:15,然后今天11点才起床没去上学2333

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define fir first
#define sec second
const int N = 2e5+5, inf = 1e9+5;
inline int read() {
char c=getchar(); int x=0,f=1;
while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
return x*f;
} int n, m, Q, w[N], x, y, lim;
char s[N];
struct meow {int u, v;} g[N]; namespace ufs {
int fa[N];
int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}
} using ufs::find; struct edge {int v, ne;} e[N<<1];
int cnt, h[N];
map<int, int> has[N];
inline void ins(int u, int v) {
if(has[u][v]) return; has[u][v] = 1;
if(find(u) == find(v)) return;
//printf("ins %d %d\n", u, v);
ufs::fa[find(u)] = find(v);
e[++cnt] = (edge) {v, h[u]}; h[u] = cnt;
e[++cnt] = (edge) {u, h[v]}; h[v] = cnt;
}
inline void link(int u, int v) {ins(u, v);}
namespace G {
struct edge {int v, ne;} e[N<<1];
int cnt, h[N];
inline void ins(int u, int v) {
e[++cnt] = (edge) {v, h[u]}; h[u] = cnt;
e[++cnt] = (edge) {u, h[v]}; h[v] = cnt;
}
int dfn[N], low[N], dfc, is_cut[N], bel[N], bcc, bcc_size[N];
struct meow {int u, v;} st[N]; int top;
void dfs(int u, int fa) {
dfn[u] = low[u] = ++dfc;
int child = 0;
for(int i=h[u]; i; i=e[i].ne) {
int v = e[i].v;
if(v == fa) continue;
meow cur_edge = (meow){u, v};
if(!dfn[v]) {
st[++top] = cur_edge;
child++;
dfs(v, u);
low[u] = min(low[u], low[v]);
if(low[v] >= dfn[u]) {
is_cut[u] = true;
bcc++;
while(true) {
meow x = st[top--];
if(bel[x.u] != bcc) {
bel[x.u] = bcc, bcc_size[bcc]++;
if(is_cut[x.u]) link(n+bcc, x.u);
}
if(bel[x.v] != bcc) {
bel[x.v] = bcc, bcc_size[bcc]++;
if(is_cut[x.v]) link(n+bcc, x.v);
}
if(x.u == u && x.v == v) break;
}
}
} else if(dfn[v] < dfn[u]) st[++top] = cur_edge, low[u] = min(low[u], dfn[v]);
}
if(fa == 0 && child == 1) is_cut[u] = false;
}
}
using G::is_cut; using G::bcc; using G::bel; using G::bcc_size; int root, no_cut = 1;
multiset<int> q[N]; void build_tree() { //for(int i=1; i<=n<<1; i++) if(is_cut[i]) printf("cut %d\n", i);
for(int i=1; i<=n; i++) bel[i] += n;// printf("bel %d %d\n", i, bel[i]);
using G::e; using G::h;
for(int u=1; u<=n; u++) {
if(is_cut[u]) {
for(int i=h[u]; i; i=e[i].ne) {
int v = e[i].v;
if(!is_cut[v]) ins(bel[v], u);
}
} else q[bel[u]].insert(w[u]);// printf("insert %d %d %d\n", u, bel[u], w[u]);
}
for(int i=1; i<=m; i++) {
int u = g[i].u, v = g[i].v; //printf("(%d, %d) %d %d\n", u, v, find(u), find(v));
if(is_cut[u] && is_cut[v] && find(u) != find(v)) ins(u, v);
}
if(is_cut[1]) root = 1;
else root = bel[1];
for(int i=1; i<=n; i++) if(is_cut[i]) no_cut = 0;
} int dfn[N], dfc, deep[N], top[N], fa[N], size[N], mx[N];
void dfs(int u) {
size[u] = 1;
for(int i=h[u]; i; i=e[i].ne) {
int v = e[i].v;
if(v == fa[u]) continue;
fa[v] = u;
deep[v] = deep[u] + 1;
if(!is_cut[u] && is_cut[v]) q[u].insert(w[v]);
dfs(v);
size[u] += size[v];
if(size[v] > size[mx[u]]) mx[u] = v;
}
}
int val[N];
void dfs(int u, int anc) {
dfn[u] = ++dfc; val[dfc] = w[u];
top[u] = anc;
if(mx[u]) dfs(mx[u], anc);
for(int i=h[u]; i; i=e[i].ne) {
int v = e[i].v;
if(v != fa[u] && v != mx[u]) dfs(v, v);
}
} namespace seg_t {
#define lc x<<1
#define rc x<<1|1
#define mid ((l+r)>>1)
#define lson lc, l, mid
#define rson rc, mid+1, r
int t[N<<2];
void build(int x, int l, int r) {
if(l == r) t[x] = val[l];
else {
build(lson);
build(rson);
t[x] = min(t[lc], t[rc]);
}
}
void cha(int x, int l, int r, int p, int v) {
if(l == r) t[x] = v;
else {
if(p <= mid) cha(lson, p, v);
else cha(rson, p, v);
t[x] = min(t[lc], t[rc]);
}
}
int que(int x, int l, int r, int ql, int qr) {
if(ql <= l && r <= qr) return t[x];
else {
int ans = inf;
if(ql <= mid) ans = min(ans, que(lson, ql, qr));
if(mid < qr) ans = min(ans, que(rson, ql, qr));
return ans;
}
}
} using seg_t::cha; using seg_t::que; void bcc_cha(int id, int u, int ww) {
q[id].erase(q[id].find(w[u]));
w[u] = ww;
q[id].insert(w[u]);
w[id] = *q[id].begin();
if(!no_cut) cha(1, 1, dfc, dfn[id], w[id]);
}
void bcc_cha2(int id, int last_w, int now_w) { //printf("bbc_cha2 %d %d %d\n", id, last_w, now_w);
q[id].erase(q[id].find(last_w));
q[id].insert(now_w);
//for(set<int>::iterator it = q[id].begin(); it != q[id].end(); it++) printf("%d ", *it); printf(" q\n");
w[id] = *q[id].begin();
cha(1, 1, dfc, dfn[id], w[id]);
} void change(int u, int ww) {
if(is_cut[u]) {
int last_w = w[u];
w[u] = ww, cha(1, 1, dfc, dfn[u], ww);
int f = fa[u]; //printf("f %d\n", f);
if(f && !is_cut[f]) bcc_cha2(f, last_w, ww);
} else bcc_cha(bel[u], u, ww);
} void query(int x, int y) {
if(x == y) {printf("%d\n", w[x]); return;}
if(!is_cut[x]) x = bel[x];
if(!is_cut[y]) y = bel[y];
//printf("query %d %d\n", x, y);
int ans = inf;
while(top[x] != top[y]) {
if(deep[top[x]] < deep[top[y]]) swap(x, y);
ans = min(ans, que(1, 1, dfc, dfn[top[x]], dfn[x]));
x = fa[top[x]];
}
if(dfn[x] > dfn[y]) swap(x, y);
ans = min(ans, que(1, 1, dfc, dfn[x], dfn[y]));
if(!is_cut[x] && fa[x]) ans = min(ans, w[fa[x]]);
printf("%d\n", ans);
} int main() {
freopen("in", "r", stdin);
n = read(); m = read(); Q = read();
for(int i=1; i<=n; i++) w[i] = read();
for(int i=1; i<=m; i++) g[i].u = read(), g[i].v = read(), G::ins(g[i].u, g[i].v);
for(int i=1; i<=n<<1; i++) ufs::fa[i] = i; G::dfs(1, 0);
build_tree();
if(no_cut) {
w[n+1] = *q[n+1].begin();
for(int i=1; i<=Q; i++) {
scanf("%s", s); x = read(); y = read();
if(s[0] == 'C') bcc_cha(n+1, x, y);
else printf("%d\n", x==y ? w[x] : w[n+1]);
}
return 0;
} dfs(root); dfs(root, root);
for(int i=1; i<=bcc; i++) w[i+n] = *q[i+n].begin(), val[dfn[i+n]] = w[i+n];
seg_t::build(1, 1, dfc); //puts("hi"); for(int i=1; i<=Q; i++) { //printf("\n--------Q----------- %d\n", i);
scanf("%s", s); x = read(); y = read();
if(s[0] == 'C') change(x, y);
else query(x, y);
}
}

CF487 E. Tourists [点双连通分量 树链剖分 割点]的更多相关文章

  1. 【Codefoces487E/UOJ#30】Tourists Tarjan 点双连通分量 + 树链剖分

    E. Tourists time limit per test: 2 seconds memory limit per test: 256 megabytes input: standard inpu ...

  2. HDU 2460 Network(双连通+树链剖分+线段树)

    HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...

  3. CF487E Tourists(圆方树+树链剖分+multiset/可删堆)

    CF487E Tourists(圆方树+树链剖分+multiset/可删堆) Luogu 给出一个带点权的无向图,两种操作: 1.修改某点点权. 2.询问x到y之间简单路径能走过的点的最小点权. 题解 ...

  4. 1103. [POI2007]MEG-Megalopolis【树链剖分】

    Description 在经济全球化浪潮的影响下,习惯于漫步在清晨的乡间小路的邮递员Blue Mary也开始骑着摩托车传递邮件了. 不过,她经常回忆起以前在乡间漫步的情景.昔日,乡下有依次编号为1.. ...

  5. 刷题总结——骑士的旅行(bzoj4336 树链剖分套权值线段树)

    题目: Description 在一片古老的土地上,有一个繁荣的文明. 这片大地几乎被森林覆盖,有N座城坐落其中.巧合的是,这N座城由恰好N-1条双 向道路连接起来,使得任意两座城都是连通的.也就是说 ...

  6. BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]

    3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2050  Solved: 817[Submit][Status ...

  7. BZOJ 1984: 月下“毛景树” [树链剖分 边权]

    1984: 月下“毛景树” Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 1728  Solved: 531[Submit][Status][Discu ...

  8. codevs 1228 苹果树 树链剖分讲解

    题目:codevs 1228 苹果树 链接:http://codevs.cn/problem/1228/ 看了这么多树链剖分的解释,几个小时后总算把树链剖分弄懂了. 树链剖分的功能:快速修改,查询树上 ...

  9. 并查集+树链剖分+线段树 HDOJ 5458 Stability(稳定性)

    题目链接 题意: 有n个点m条边的无向图,有环还有重边,a到b的稳定性的定义是有多少条边,单独删去会使a和b不连通.有两种操作: 1. 删去a到b的一条边 2. 询问a到b的稳定性 思路: 首先删边考 ...

随机推荐

  1. nodeJs文件系统(fs)与流(stream)

    一.简介 本文将介绍node.js文件系统(fs)和流(stream)的一些API已经参数使用情况. 二.目录 文件系统将介绍以下方法: 1.fs.readFile 2.fs.writeFile 3. ...

  2. C#面试常见题目

    1.CTS.CLS.CLR分别作何解释 CTS:Common Type System 通用系统类型.Int32.Int16→int.String→string.Boolean→bool CLS:Com ...

  3. SDK是什么?什么是SDK

    从 SDK导航 看到的 应该比较专业! SDK的英文全名是:software development kit,翻译成中文的意思就是"软件开发工具包" 通俗一点的理解,是指由第三方服 ...

  4. android 基础04-BroadCastReceiver

    Android 系统中的广播(BroadCast) 是组件与组件进行的一种可跨线程的通信方式.类似于 广播者-订阅者(publish-subscribe) 的实现,当系统或者某个应用的状态发生改变时, ...

  5. asp.net -mvc框架复习(11)-基于三层架构与MVC实现完整的用户登录

    一.先从M部分写起(Modles\DAL\BLL) 1.Modles 实体类:上次实体类已经搞定. 2.DAL 数据访问类类 (1)通用数据数据访问类: A:  先编写数据连接字符串,写到网站根目录W ...

  6. Python调用外部程序——os.system()和subprocess.call

    通过os.system函数调用其他程序 预备知识:cmd中打开和关闭程序 cmd中打开程序 a.打开系统自带程序 系统自带的程序的路径一般都已加入环境变量之中,只需在cmd窗口中直接输入程序名称即可. ...

  7. FPGA上如何求32个输入的最大值和次大值:分治

    上午在论坛看到个热帖,里头的题目挺有意思的,简单的记录了一下. 0. 题目 在FPGA上实现一个模块,求32个输入中的最大值和次大值,32个输入由一个时钟周期给出.(题目来自论坛,面试题,如果觉得不合 ...

  8. 通过Azure Powershell获取asm及arm虚拟机的配置信息

    1.asm虚拟机可以使用类似如下Azure Powershell命令获取虚拟机的基本信息,包括发行版本,虚拟机名称及size[备注:虚拟机需要是使用平台image创建的] PS C:\Users\he ...

  9. margin 和 padding 的本质区别

    问题? 如何弄清 margin 和 padding之间的区别? 那,答案呢? margin 边界, padding 填充 假如有一个盒子,padding就相当于盒子的厚度,盒子大小固定,通过修改pad ...

  10. common-logging源码解析

    OK,现在我们来研究下common-logging的源码.这篇博客有参照上善若水的博客,感谢他的无私分享. 先来随便扯点吧,貌似所有这些流行的Logging框架都和Log4J多少有点关系(不太确定Co ...