圆方树总结 [uoj30]Tourists
圆方树总结
所谓圆方树就是把一张图变成一棵树。
怎么变啊qaq
这里盗一张图

简单来说就是给每一个点双新建一个点,然后连向这个点双中的每一个点。特殊的,把两个点互相连通的也视作一个点双。
我们把原来就有的点称作圆点,因点双而新建的点称之为方点。
这样这棵圆方树就会有一个这样的性质:和每个圆点(方点)相连的点一定是方点(圆点)。
我们在每个圆点上维护这个点原本的信息,在方点上维护这个点双的信息,这样就能完成一些关于一般图的所有简单路径的询问了。
例如:我现在有一张一般图,每个点有一个点权,要求从\(u\)到\(v\)的所有简单路径中经过的最小点权是多少。
可以建出圆方树,在每个方点上维护这个点双中的最小点权,那么每次询问就是查询一个路径最小值了。
如果有修改怎么办呢?直接改完圆点后改和它相邻的方点?
显然这个复杂度是\(O(度数)\)的,很容易卡成\(O(n^2)\)
方法:每个方点维护的信息中不包括它的父亲圆点,这样修改圆点的时候就只需要修改它的父亲方点。查询的时候如果路径的\(lca\)是个方点,就还要再算上它的父亲圆点。
是不是很妙?
uoj30
就是上面讲的那个东西。
圆方树+可删除堆+树链剖分+线段树
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
int gi(){
int x=0,w=1;char ch=getchar();
while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if (ch=='-') w=0,ch=getchar();
while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return w?x:-x;
}
const int N = 4e5+5;
int n,tot,m,q,val[N],dfn[N],low[N],tim,S[N];
int fa[N],dep[N],sz[N],son[N],top[N],mn[N<<2];
struct Set{
priority_queue<int,vector<int>,greater<int> >Q1,Q2;
void insert(int x){Q1.push(x);}
void erase(int x){Q2.push(x);}
int top(){
while (!Q2.empty()&&Q1.top()==Q2.top()) Q1.pop(),Q2.pop();
return Q1.top();
}
}Q[N];
struct Graph{
int to[N],nxt[N],head[N],cnt;
void link(int u,int v){
to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
to[++cnt]=u;nxt[cnt]=head[v];head[v]=cnt;
}
}G1,G2;
void Tarjan(int u){
dfn[u]=low[u]=++tim;S[++S[0]]=u;
for (int e=G1.head[u];e;e=G1.nxt[e]){
int v=G1.to[e];
if (!dfn[v]){
Tarjan(v),low[u]=min(low[u],low[v]);
if (low[v]>=dfn[u]){
G2.link(++tot,u);int x=0;
do{
x=S[S[0]--];G2.link(tot,x);
}while (x!=v);
}
}
else low[u]=min(low[u],dfn[v]);
}
}
void dfs1(int u,int f){
fa[u]=f;dep[u]=dep[f]+1;sz[u]=1;
if (u<=n&&f) Q[f].insert(val[u]);
for (int e=G2.head[u];e;e=G2.nxt[e]){
int v=G2.to[e];if (v==f) continue;
dfs1(v,u);sz[u]+=sz[v];
if (sz[v]>sz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int up){
top[u]=up;dfn[u]=++tim;
if (son[u]) dfs2(son[u],up);
for (int e=G2.head[u];e;e=G2.nxt[e]){
int v=G2.to[e];if (v==fa[u]||v==son[u]) continue;
dfs2(v,v);
}
}
void modify(int x,int l,int r,int p,int v){
if (l==r) {mn[x]=v;return;}
int mid=l+r>>1;
if (p<=mid) modify(x<<1,l,mid,p,v);
else modify(x<<1|1,mid+1,r,p,v);
mn[x]=min(mn[x<<1],mn[x<<1|1]);
}
int query(int x,int l,int r,int ql,int qr){
if (l>=ql&&r<=qr) return mn[x];
int mid=l+r>>1;
if (qr<=mid) return query(x<<1,l,mid,ql,qr);
if (ql>mid) return query(x<<1|1,mid+1,r,ql,qr);
return min(query(x<<1,l,mid,ql,qr),query(x<<1|1,mid+1,r,ql,qr));
}
int main(){
tot=n=gi();m=gi();q=gi();
for (int i=1;i<=n;++i) val[i]=gi();
while (m--){
int u=gi(),v=gi();
G1.link(u,v);
}
for (int i=1;i<=n;++i) if (!dfn[i]) Tarjan(i);
tim=0;dfs1(1,0),dfs2(1,1);
for (int i=1;i<=n;++i) modify(1,1,tot,dfn[i],val[i]);
for (int i=n+1;i<=tot;++i) modify(1,1,tot,dfn[i],Q[i].top());
while (q--){
char ch='%';while (ch!='A'&&ch!='C') ch=getchar();
if (ch=='C'){
int a=gi(),b=gi();
if (fa[a]) Q[fa[a]].erase(val[a]);
val[a]=b;modify(1,1,tot,dfn[a],val[a]);
if (fa[a]) Q[fa[a]].insert(val[a]),modify(1,1,tot,dfn[fa[a]],Q[fa[a]].top());
}
else{
int u=gi(),v=gi(),ans=2e9;
while (top[u]^top[v]){
if (dep[top[u]]<dep[top[v]]) swap(u,v);
ans=min(ans,query(1,1,tot,dfn[top[u]],dfn[u]));
u=fa[top[u]];
}
if (dep[u]>dep[v]) swap(u,v);
ans=min(ans,query(1,1,tot,dfn[u],dfn[v]));
if (u>n) ans=min(ans,val[fa[u]]);
printf("%d\n",ans);
}
}
return 0;
}
圆方树与仙人掌
留坑待补
圆方树总结 [uoj30]Tourists的更多相关文章
- 【学习笔记】圆方树(CF487E Tourists)
终于学了圆方树啦~\(≧▽≦)/~ 感谢y_immortal学长的博客和帮助 把他的博客挂在这里~ 点我传送到巨佬的博客QwQ! 首先我们来介绍一下圆方树能干什么呢qwq 1.将图上问题简化到树上问题 ...
- 圆方树简介(UOJ30:CF Round #278 Tourists)
我写这篇博客的原因 证明我也是学过圆方树的 顺便存存代码 前置技能 双联通分量:点双 然后就没辣 圆方树 建立 新建一个图 定义原图中的所有点为圆点 对于每个点双联通分量(只有两个点的也算) 建立一个 ...
- uoj30【CF Round #278】Tourists(圆方树+树链剖分+可删除堆)
- 学习了一波圆方树 学习了一波点分治 学习了一波可删除堆(巧用 ? STL) 传送门: Icefox_zhx 注意看代码看怎么构建圆方树的. tips:tips:tips:圆方树内存记得开两倍 CO ...
- 【CF487E】Tourists(圆方树)
[CF487E]Tourists(圆方树) 题面 UOJ 题解 首先我们不考虑修改,再来想想这道题目. 我们既然要求的是最小值,那么,在经过一个点双的时候,走的一定是具有较小权值的那一侧. 所以说,我 ...
- UOJ#30/Codeforces 487E Tourists 点双连通分量,Tarjan,圆方树,树链剖分,线段树
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ30.html 题目传送门 - UOJ#30 题意 uoj写的很简洁.清晰,这里就不抄一遍了. 题解 首先建 ...
- Tourists——圆方树
CF487E Tourists 一般图,带修求所有简单路径代价. 简单路径,不能经过同一个点两次,那么每个V-DCC出去就不能再回来了. 所以可以圆方树,然后方点维护一下V-DCC内的最小值. 那么, ...
- CF487E Tourists(圆方树+树链剖分+multiset/可删堆)
CF487E Tourists(圆方树+树链剖分+multiset/可删堆) Luogu 给出一个带点权的无向图,两种操作: 1.修改某点点权. 2.询问x到y之间简单路径能走过的点的最小点权. 题解 ...
- Codeforces 487E Tourists [广义圆方树,树链剖分,线段树]
洛谷 Codeforces 思路 首先要莫名其妙地想到圆方树. 建起圆方树后,令方点的权值是双联通分量中的最小值,那么\((u,v)\)的答案就是路径\((u,v)\)上的最小值. 然而这题还有修改, ...
- CF487E Tourists 圆方树、树链剖分
传送门 注意到我们需要求的是两点之间所有简单路径中最小值的最小值,那么对于一个点双联通分量来说,如果要经过它,则一定会经过这个点双联通分量里权值最小的点 注意:这里不能缩边双联通分量,样例\(2\)就 ...
随机推荐
- 20145201《Java程序设计》第7周学习总结
20145201 <Java程序设计>第七周学习总结 教材学习内容总结 本周学习了课本第十二.十三章内容,即Lambda.时间与日期 第十二章 Lambda 12.1 认识Lambda语法 ...
- 第十节课-RNN介绍
2017-08-21 这次的课程介绍了RNN的相关知识: 首先是RNN的几种模型: 分别又不同的应用场景,包括机器翻译,视频的分类... RNN的解释: 主要的特点就是用到了上一个隐含状态的信息,所以 ...
- Mysql 基本用法
Java中两种常用的数据库: MYSQL Oracle MYSQL :开源免费的数据库,小型的数据库.由瑞典MySQL AB 公司开发,适合中小企业使用,由C语言和C++编写的.已经被Ora ...
- scjp考试准备 - 8 - final关键字
题目,如下代码的执行结果: import java.util.ArrayList; class Pizza{ ArrayList toppings; public final void addTopp ...
- js关闭浏览器窗口及检查浏览器关闭事件
js关闭浏览器窗口,不弹出提示框.支持ie6+,火狐,谷歌等浏览器,下面以一个示例为大家详细介绍下具体的实现方法,感兴趣的朋友可以参考下 js关闭浏览器窗口 js关闭浏览器窗口,不弹出提示框.支持 ...
- Pycharm for mac 快捷键
cmd b 跳转到声明处(cmd加鼠标) opt + 空格 显示符号代码 (esc退出窗口 回车进入代码) cmd []光标之前/后的位置 opt + F7 find usage cmd backsp ...
- IOS-Alcatraz(插件管理工具)
一.简单说明 Alcatraz 是一款 Xcode的插件管理工具,可以用来管理XCode的 插件.模版以及颜色配置的工具. 二.如何安装 1.github地址:https://github.com/a ...
- 使用Spring实现MySQL读写分离
1. 为什么要进行读写分离 大量的JavaWeb应用做的是IO密集型任务, 数据库的压力较大, 需要分流 大量的应用场景, 是读多写少, 数据库读取的压力更大 一个很自然的思路是使用一主多从的数据库集 ...
- ARM汇编指令集1
(汇编)指令是CPU机器指令的助记符,经过编译过会得到一串0011组成的机器码,可以由CPU读取执行. (汇编)伪指令本质不是指令(只是和指令一起写在代码中),它是编译器环境提供的,目的是用来指导编译 ...
- Fiddler工作原理与代理设置
1,什么是Fiddler Fiddler是一个http协议调试代理工具,它能够记录客户端和服务器之间的所有 HTTP请求,可以针对特定的HTTP请求,分析请求数据.设置断点.调试web应用.修改请求的 ...