我写这篇博客的原因

证明我也是学过圆方树的

顺便存存代码


前置技能

双联通分量:点双

然后就没辣

圆方树

建立

新建一个图

定义原图中的所有点为圆点

对于每个点双联通分量(只有两个点的也算)

建立一个方点,向所有的点双内的点连边

性质

  1. 一定是个森林
  2. 每个点双有唯一的方点
  3. 圆点方点相间分布,相同点不相邻

等等

例子 1

题面

求可以出现在两点之间的简单路路径上的点的最大权值,不带修改

分析

考虑用圆方树来解决

设圆点权值为本身,方点权值为点双中的最大权值

那么就是树上的路径最大权值

例子 2

还是上面的题,可以修改一个点的权值

类似题UOJ

用老方法

每次修改时更改圆点连接的所有方点

没了?

不存在的,这样每次修改是\(O(n)\)的,容易被卡

换一种定义:方点权值不包括它的父亲圆点

那么每次修改就只要修改圆点的父亲

注意如果\(lca\)是方点,还要算上它父亲方点的权值

堆+线段树(zkw辣)+树剖+圆方树+tarjan

UOJ代码

# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int _(4e5 + 5); IL int Input(){
RG int x = 0, z = 1; RG char c = getchar();
for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
return x * z;
} struct Edge{
int next[_], first[_], to[_], cnt; IL void Init(){
Fill(first, -1);
} IL void Add(RG int u, RG int v){
next[cnt] = first[u], to[cnt] = v, first[u] = cnt++;
}
} G1, G2;
struct Segment{
int mn[_ << 2], M; IL void Init(RG int n){
Fill(mn, 127);
for(M = 1; M < n; M <<= 1);
} IL void Update(RG int x, RG int y){
x += M - 1, mn[x] = y;
for(x >>= 1; x; x >>= 1) mn[x] = min(mn[x << 1], mn[x << 1 | 1]);
} IL int Query(RG int l, RG int r){
RG int ret = 2e9;
for(l += M - 2, r += M; l ^ r ^ 1; l >>= 1, r >>= 1){
if(~l & 1) ret = min(ret, mn[l ^ 1]);
if(r & 1) ret = min(ret, mn[r ^ 1]);
}
return ret;
}
} T;
struct Heap{
priority_queue <int> Q1, Q2; IL void Push(RG int x){
Q1.push(-x);
} IL void Del(RG int x){
Q2.push(-x);
} IL int Top(){
while(!Q2.empty() && Q1.top() == Q2.top()) Q1.pop(), Q2.pop();
return -Q1.top();
}
} Q[_];
int tmp, n, m, q, val[_], dfn[_], low[_], Index, S[_];
int size[_], top[_], fa[_], deep[_], son[_]; IL void Tarjan(RG int u){
dfn[u] = low[u] = ++Index, S[++S[0]] = u;
for(RG int e = G1.first[u]; e != -1; e = G1.next[e]){
RG int v = G1.to[e], x;
if(!dfn[v]){
Tarjan(v), low[u] = min(low[u], low[v]);
if(low[v] >= dfn[u]){
val[++n] = 2e9, x = 0;
do{
x = S[S[0]--];
G2.Add(n, x), G2.Add(x, n);
} while(x != v);
G2.Add(n, u), G2.Add(u, n);
}
}
else low[u] = min(low[u], dfn[v]);
}
} IL void Dfs1(RG int u){
size[u] = 1;
if(u <= tmp && fa[u]) Q[fa[u]].Push(val[u]);
for(RG int e = G2.first[u]; e != -1; e = G2.next[e]){
RG int v = G2.to[e];
if(size[v]) continue;
fa[v] = u, deep[v] = deep[u] + 1;
Dfs1(v);
size[u] += size[v];
if(size[v] > size[son[u]]) son[u] = v;
}
} IL void Dfs2(RG int u, RG int Top){
dfn[u] = ++Index, top[u] = Top;
if(son[u]) Dfs2(son[u], Top);
for(RG int e = G2.first[u]; e != -1; e = G2.next[e])
if(!dfn[G2.to[e]]) Dfs2(G2.to[e], G2.to[e]);
} IL int Query(RG int u, RG int v){
RG int ret = 2e9;
while(top[u] ^ top[v]){
if(deep[top[u]] > deep[top[v]]) swap(u, v);
ret = min(ret, T.Query(dfn[top[v]], dfn[v]));
v = fa[top[v]];
}
if(dfn[u] > dfn[v]) swap(u, v);
ret = min(ret, T.Query(dfn[u], dfn[v]));
if(u > tmp) ret = min(ret, val[fa[u]]);
return ret;
} int main(RG int argc, RG char* argv[]){
G1.Init(), G2.Init();
tmp = n = Input(), m = Input(), q = Input();
for(RG int i = 1; i <= n; ++i) val[i] = Input();
for(RG int i = 1; i <= m; ++i){
RG int u = Input(), v = Input();
G1.Add(u, v), G1.Add(v, u);
}
for(RG int i = 1; i <= tmp; ++i) if(!dfn[i]) Tarjan(i);
Fill(dfn, 0), Index = 0, T.Init(n);
Dfs1(1), Dfs2(1, 1);
for(RG int i = 1; i <= n; ++i) T.Update(dfn[i], val[i]);
for(RG int i = tmp + 1; i <= n; ++i) T.Update(dfn[i], Q[i].Top());
for(RG int i = 1, a, b; i <= q; ++i){
RG char op; scanf(" %c", &op);
a = Input(), b = Input();
if(op == 'C'){
if(fa[a]) Q[fa[a]].Del(val[a]);
val[a] = b, T.Update(dfn[a], val[a]);
if(fa[a]) Q[fa[a]].Push(val[a]);
if(fa[a]) T.Update(dfn[fa[a]], Q[fa[a]].Top());
}
else printf("%d\n", Query(a, b));
}
return 0;
}

圆方树简介(UOJ30:CF Round #278 Tourists)的更多相关文章

  1. UOJ #30. [CF Round #278] Tourists

    UOJ #30. [CF Round #278] Tourists 题目大意 : 有一张 \(n\) 个点, \(m\) 条边的无向图,每一个点有一个点权 \(a_i\) ,你需要支持两种操作,第一种 ...

  2. 圆方树总结 [uoj30]Tourists

    圆方树总结 所谓圆方树就是把一张图变成一棵树. 怎么变啊qaq 这里盗一张图 简单来说就是给每一个点双新建一个点,然后连向这个点双中的每一个点.特殊的,把两个点互相连通的也视作一个点双. 我们把原来就 ...

  3. [CF Round #278] Tourists

    给定一个n个点m条边的无向图,求图上的两点的所有的简单路径之间的最小边. 蓝链 $ n,m,q \leq 100000, w_i \leq 10 ^7$ Solution 考虑建立用缩点双来建立广义圆 ...

  4. uoj30【CF Round #278】Tourists(圆方树+树链剖分+可删除堆)

    - 学习了一波圆方树 学习了一波点分治 学习了一波可删除堆(巧用 ? STL) 传送门: Icefox_zhx 注意看代码看怎么构建圆方树的. tips:tips:tips:圆方树内存记得开两倍 CO ...

  5. UOJ#30/Codeforces 487E Tourists 点双连通分量,Tarjan,圆方树,树链剖分,线段树

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ30.html 题目传送门 - UOJ#30 题意 uoj写的很简洁.清晰,这里就不抄一遍了. 题解 首先建 ...

  6. 仙人掌 && 圆方树 && 虚树 总结

    仙人掌 && 圆方树 && 虚树 总结 Part1 仙人掌 定义 仙人掌是满足以下两个限制的图: 图完全联通. 不存在一条边处在两个环中. 其中第二个限制让仙人掌的题做 ...

  7. BZOJ5329:[SDOI2018]战略游戏(圆方树,虚树)

    Description 省选临近,放飞自我的小Q无心刷题,于是怂恿小C和他一起颓废,玩起了一款战略游戏. 这款战略游戏的地图由n个城市以及m条连接这些城市的双向道路构成,并且从任意一个城市出发总能沿着 ...

  8. 仙人掌&圆方树

    仙人掌&圆方树 Tags:图论 [x] [luogu4320]道路相遇 https://www.luogu.org/problemnew/show/P4320 [ ] [SDOI2018]战略 ...

  9. UOJ.87.mx的仙人掌(圆方树 虚树)(未AC)

    题目链接 本代码10分(感觉速度还行..). 建圆方树,预处理一些东西.对询问建虚树. 对于虚树上的圆点直接做:对于方点特判,枚举其所有儿子,如果子节点不在该方点代表的环中,跳到那个点并更新其val, ...

随机推荐

  1. Java并发编程Semaphore

    信号量 信号量类Semaphore,用来保护对唯一共享资源的访问.一个简单的打印队列,并发任务进行打印,加入信号量同时之能有一个线程进行打印任务 . import java.util.concurre ...

  2. elasticsearch 6 在 centos 6 上的安装问题

    ERROR: bootstrap checks failed max file descriptors [4096] for elasticsearch process likely too low, ...

  3. 2017年 Java 程序员,风光背后的危机

    不得不承认,经历过行业的飞速发展期,互联网的整体发展趋于平稳.为什么这么说?为什么要放在 Java 程序员的盘点下说? 的确,对于进可攻前端,后可守后端大本营的 Java 程序员而言,虽然供应逐年上涨 ...

  4. 在gitlab上面创建私有库

    一.创建私有库1.使用xcode建立新的工程,选择Cocoa Touch Static Library,取名为podTest   WechatIMG1172.jpeg 2.创建一个类PodTest,给 ...

  5. 老男孩Python全栈开发(92天全)视频教程 自学笔记09

    day9课程内容: 乌班图(ubuntu)64位系统 和 VMware 虚拟机安装(官网收费又麻烦,在网上找资源 安装vmware: vm运行(秘钥找度娘)--文件--新建虚拟机--自定义 下一步-- ...

  6. 关于UIButton嵌入到UIView点击无反应问题的解决方法和delegate的简单用法示例(转载)

    做项目封装UIView的时候碰到的问题,没想到有个哥们儿还写成博客,特此收藏! 问题是这样的,几个界面用到同一个自定义返回按钮,于是就想着把这个按钮单独封装起来,添加一个UIView类,在里面自定义U ...

  7. 2018/3/2晚11点30分写的程序(C++)

    程序目标:输入一个字符串,竖向输出该字符串.使用string和动态分配内存机制.代码如下: #include<iostream>#include "stdafx.h"# ...

  8. ubuntu设置网络

    二 .设置无线网络 1.首先确认一下你的无线驱动已经安装 方法一,查看一下ubuntu右上角的网络设置中有无线连接,如果有说明已经驱动了,ubuntu自带的就会驱动无线网卡. 方法二,iwconfig ...

  9. C语言结构体定义的几种方法

    什么是结构体? 在C语言中,结构体(struct)指的是一种数据结构,是C语言中聚合数据类型(aggregate data type)的一类.结构体可以被声明为变量.指针或数组等,用以实现较复杂的数据 ...

  10. 云计算基础 (redhat7介绍及相关配置)

    redhat7简介 新版本的rhel7不再对32位架构的支持 引导程序: GRUB2,比之前的GRUB更强大,GRUB2支持bios,efi和openfiremware GRUB2支持mbr分区表和g ...