CF487E Tourists

一般图,带修求所有简单路径代价。

简单路径,不能经过同一个点两次,那么每个V-DCC出去就不能再回来了。

所以可以圆方树,然后方点维护一下V-DCC内的最小值。

那么,从任意一个割点进入这个DCC,必然可以绕一圈再从另一个割点出去。

所以,路径上的最小值,就是圆方树路径上的最小值。方点的最小值就是在这个DCC中走一走得到的。

树链剖分+线段树维护路径

用堆维护方点四周的圆点的最小值。然后更新。

一个问题是:

更新一个割点圆点,会影响到四周所有的方点。暴力更新,菊花图直接TLE

这样更新:

方点只维护圆方树上儿子圆点的最值。

这样,每次修改圆点,只要修改father的方点的值即可。

查询路径的时候,如果LCA是方点,那么把这个方点的father的值也取min即可。

圆点就无所谓了。LCA自己一定会取到的。

代码:

#include<bits/stdc++.h>
#define reg register int
#define mid ((l+r)>>1)
#define il inline
#define numb (ch^'0')
using namespace std;
typedef long long ll;
il void rd(int &x){
char ch;x=;bool fl=false;
while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
for(x=numb;isdigit(ch=getchar());x=x*+numb);
(fl==true)&&(x=-x);
}
namespace Miracle{
const int N=2e5+;
const int inf=0x3f3f3f3f;
int n,m,q;
struct node{
int nxt,to;
}e[*N],bian[*N];
int hd[N],pre[N];
int cnt1,cnt2;
void _add(int x,int y){
bian[++cnt1].nxt=pre[x];
bian[cnt1].to=y;
pre[x]=cnt1;
}
void add(int x,int y){
e[++cnt2].nxt=hd[x];
e[cnt2].to=y;
hd[x]=cnt2;
}
struct heap{
priority_queue<int,vector<int>,greater<int> >h,d;
int top(){
while(h.size()&&d.size()&&h.top()==d.top()){
h.pop();d.pop();
}
if(h.empty()) return inf;
return h.top();
}
void push(int c){
h.push(c);
}
void dele(int c){
d.push(c);
}
}f[N];
int w[N];
int tot,df;
int dfn[N],low[N],sta[N],tp;
void tarjan(int x){
dfn[x]=low[x]=++df;
sta[++tp]=x;
for(reg i=pre[x];i;i=bian[i].nxt){
int y=bian[i].to;
if(!dfn[y]){
tarjan(y);
low[x]=min(low[x],low[y]);
if(dfn[x]<=low[y]){
++tot;//fang
w[tot]=inf;//warning!!!
int z;
do{
z=sta[tp--];
add(tot,z);add(z,tot);
}while(z!=y);
add(x,tot);add(tot,x);
}
}
else low[x]=min(low[x],dfn[y]);
}
}
int dep[N],fa[N],top[N],fdfn[N],son[N],sz[N];
void dfs1(int x,int d){
dep[x]=d;
sz[x]=;
for(reg i=hd[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa[x]) continue;
fa[y]=x;
dfs1(y,d+);
sz[x]+=sz[y];
if(sz[y]>sz[son[x]]) son[x]=y;
if(x>n){//a fang
f[x].push(w[y]);
w[x]=min(w[x],w[y]);
}
}
}
void dfs2(int x){
dfn[x]=++df;
fdfn[df]=x;
if(!top[x]) top[x]=x;
if(son[x]) top[son[x]]=top[x],dfs2(son[x]);
for(reg i=hd[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa[x]) continue;
if(y==son[x]) continue;
dfs2(y);
}
}
int mi[*N];
void pushup(int x){
mi[x]=min(mi[x<<],mi[x<<|]);
}
void build(int x,int l,int r){
if(l==r){
mi[x]=w[fdfn[l]];return;
}
build(x<<,l,mid);
build(x<<|,mid+,r);
pushup(x);
}
void chan(int x,int l,int r,int to,int c){
if(l==r){
mi[x]=c;return;
}
if(to<=mid) chan(x<<,l,mid,to,c);
else chan(x<<|,mid+,r,to,c);
pushup(x);
}
int query(int x,int l,int r,int L,int R){
if(L<=l&&r<=R){
return mi[x];
}
int ret=inf;
if(L<=mid) ret=min(ret,query(x<<,l,mid,L,R));
if(mid<R) ret=min(ret,query(x<<|,mid+,r,L,R));
return ret;
}
int wrk(int x,int y){
int ret=inf;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ret=min(ret,query(,,tot,dfn[top[x]],dfn[x]));
x=fa[top[x]];
}
if(dep[x]<dep[y]) swap(x,y);
ret=min(ret,query(,,tot,dfn[y],dfn[x]));
if(y>n) ret=min(ret,w[fa[y]]);
return ret;
}
int main(){
rd(n);rd(m);rd(q);
for(reg i=;i<=n;++i)rd(w[i]);
int x,y;
for(reg i=;i<=m;++i){
rd(x);rd(y);
_add(x,y);_add(y,x);
}
tot=n;
tarjan();
memset(dfn,,sizeof dfn);
df=;
dfs1(,);
dfs2();
build(,,tot);
char ch[];
while(q--){
scanf("%s",ch+);
if(ch[]=='A'){
rd(x);rd(y);
printf("%d\n",wrk(x,y));
}
else{
rd(x);rd(y);
int ff=fa[x];
f[ff].dele(w[x]);
f[ff].push(y);
int tmp=f[ff].top();
chan(,,tot,dfn[ff],tmp);
w[ff]=tmp;//no use in fact
w[x]=y;
chan(,,tot,dfn[x],y);
}
}
return ;
} }
int main(){
Miracle::main();
return ;
} /*
Author: *Miracle*
Date: 2018/11/30 16:10:40
*/

Tourists——圆方树的更多相关文章

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

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

  2. CF487E Tourists 圆方树、树链剖分

    传送门 注意到我们需要求的是两点之间所有简单路径中最小值的最小值,那么对于一个点双联通分量来说,如果要经过它,则一定会经过这个点双联通分量里权值最小的点 注意:这里不能缩边双联通分量,样例\(2\)就 ...

  3. CF487E Tourists[圆方树+树剖(线段树套set)]

    做这题的时候有点怂..基本已经想到正解了..结果感觉做法有点假,还是看了正解题解.. 首先提到简单路径上经过的点,就想到了一个关于点双的结论:两点间简单路径上所有可能经过的点的并等于路径上所有点所在点 ...

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

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

  5. CF487E Tourists + 圆方树学习笔记(圆方树+树剖+线段树+multiset)

    QWQ果然我已经什么都学不会的人了. 这个题目要求的是图上所有路径的点权和!QWQ(我只会树上啊!) 这个如果是好啊 这时候就需要 圆方树! 首先在介绍圆方树之前,我们先来一点简单的前置知识 首先,我 ...

  6. 【CF487E】Tourists(圆方树)

    [CF487E]Tourists(圆方树) 题面 UOJ 题解 首先我们不考虑修改,再来想想这道题目. 我们既然要求的是最小值,那么,在经过一个点双的时候,走的一定是具有较小权值的那一侧. 所以说,我 ...

  7. 【学习笔记】圆方树(CF487E Tourists)

    终于学了圆方树啦~\(≧▽≦)/~ 感谢y_immortal学长的博客和帮助 把他的博客挂在这里~ 点我传送到巨佬的博客QwQ! 首先我们来介绍一下圆方树能干什么呢qwq 1.将图上问题简化到树上问题 ...

  8. 圆方树简介(UOJ30:CF Round #278 Tourists)

    我写这篇博客的原因 证明我也是学过圆方树的 顺便存存代码 前置技能 双联通分量:点双 然后就没辣 圆方树 建立 新建一个图 定义原图中的所有点为圆点 对于每个点双联通分量(只有两个点的也算) 建立一个 ...

  9. Codeforces 487E Tourists [广义圆方树,树链剖分,线段树]

    洛谷 Codeforces 思路 首先要莫名其妙地想到圆方树. 建起圆方树后,令方点的权值是双联通分量中的最小值,那么\((u,v)\)的答案就是路径\((u,v)\)上的最小值. 然而这题还有修改, ...

随机推荐

  1. thinkphp5数据库导入Excel表格

    $data=$order_info; //$data 你要下载谁 就去查谁 // $data= Db::name('order_info') // ->field('consignee,tel, ...

  2. 20190105-打印字母C,H,N,口等图像和杨辉三角

    1. 打印字母C ****** * * * * ****** def print_c(n): print('*' * n) for i in range(n): print('* ') print(' ...

  3. linux网络服务实验

    1.设置window IP地址为192.168.3.XX,掩码24位. 2.设置Linux IP地址为192.168.3.YY,掩码24位.window与Linux互相ping通. 3.在linux中 ...

  4. go学习笔记-流程控制(if/else,for/range)

    流程控制(if/else,for/range) if if条件判断语句的语法概括起来就是:如果满足条件就做某事,否则做另一件事. func testIf() { num := 10 if num &l ...

  5. 二叉树和二叉查找树--数据结构与算法JavaScript描述(10)

    二叉树和二叉查找树 概念 树是一种非线性的数据结构,以分层的方式存储数据. 树被用来存储具有层级关系的数据,比如文件系统的文件: 树还被用来存储有序列表. 一棵树最上面的节点称为根节点. 如果一个节点 ...

  6. 【Java】关于Spring框架的总结 (一)

    本文总结一些关于Spring框架的理解,注意点及基础操作.如果有不对的地方,欢迎批评和建议.大家一起努力吧! Spring 框架简介 Spring 是一个开源框架,是为了解决企业应用程序开发复杂性而创 ...

  7. HDU 5530:Pipes Selection

    题意: 给定长度为\(L\),元素总和为\(S\)的非负整数序列\(A\),对于每一个\(1 \leq i \leq S\),求出:所有满足\(\sum_{j=l}^rA_j=i\)的二元组\((l, ...

  8. Android Studio modify language level to Java 8

    If you need use lambda, should modify language level File -> Project Structure -> app -> Pr ...

  9. Django学习之天气调查实例(2):显示数据表数据

    数据表数据添加后,如添加3条用户信息,分别为“aaa”.“bbb”.“ccc”,现在通过代码的方式显示数据表中的数据. 1.在website项目文件夹中创建 userload.py文件,并且写如下代码 ...

  10. [bzoj5158][Tjoi2014]Alice and Bob

    好羞愧啊最近一直在刷水... 题意:给定序列$c$的$a_i$,构造出一个序列$c$使得$\sum b_i$最大. 其中$a_i$表示以$c_i$结尾的最长上升子序列长度,$b_i$表示以$c_i$为 ...