Tourists——圆方树
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=0;bool fl=false;while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);for(x=numb;isdigit(ch=getchar());x=x*10+numb);(fl==true)&&(x=-x); } namespace Miracle{ const int N=2e5+5; const int inf=0x3f3f3f3f; int n,m,q; struct node{int nxt,to; }e[2*N],bian[2*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;//fangw[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]=1;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+1);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[4*N]; void pushup(int x){mi[x]=min(mi[x<<1],mi[x<<1|1]); } void build(int x,int l,int r){if(l==r){mi[x]=w[fdfn[l]];return;}build(x<<1,l,mid);build(x<<1|1,mid+1,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<<1,l,mid,to,c);else chan(x<<1|1,mid+1,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<<1,l,mid,L,R));if(mid<R) ret=min(ret,query(x<<1|1,mid+1,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(1,1,tot,dfn[top[x]],dfn[x]));x=fa[top[x]];}if(dep[x]<dep[y]) swap(x,y);ret=min(ret,query(1,1,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=1;i<=n;++i)rd(w[i]);int x,y;for(reg i=1;i<=m;++i){rd(x);rd(y);_add(x,y);_add(y,x);}tot=n;tarjan(1);memset(dfn,0,sizeof dfn);df=0;dfs1(1,1);dfs2(1);build(1,1,tot);char ch[10];while(q--){scanf("%s",ch+1);if(ch[1]=='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(1,1,tot,dfn[ff],tmp);w[ff]=tmp;//no use in factw[x]=y;chan(1,1,tot,dfn[x],y);}}return 0; }} int main(){Miracle::main();return 0; }/*Author: *Miracle*Date: 2018/11/30 16:10:40 */
转载于:https://www.cnblogs.com/Miracevin/p/10045891.html
Tourists——圆方树相关推荐
- 【学习笔记】圆方树(CF487E Tourists)
终于学了圆方树啦~\(≧▽≦)/~ 感谢y_immortal学长的博客和帮助 把他的博客挂在这里~ 点我传送到巨佬的博客QwQ! 首先我们来介绍一下圆方树能干什么呢qwq 1.将图上问题简化到树上问题 ...
- 【CF487E】Tourists【圆方树】【树链剖分】【multiset】
题意:给一张 nnn 点 mmm 边的连通无向图,点帯权,qqq 次操作: 修改一个点的权值. 询问两点间所有简单路的最小权值的最小值. n,m,q≤105n,m,q\leq 10^5n,m,q≤10 ...
- 广义圆方树+树链剖分+set(Codeforces Round #278 (Div. 1): E. Tourists)
前置:双联通分量.圆方树.树链剖分 什是是广义圆方树 圆方树是针对于仙人掌建树,而广义圆方树是针对无向图建树,对于一个无向图 无向图中的所有点 → 广义圆方树中的所有圆点 无向图中的一个双联通分量 → ...
- CF487E Tourists(圆方树+树链剖分)
洛谷题目传送门 解题思路 不会圆方树的可以看我的博客圆方树学习记录及例题 首先Tarjan寻找点双连通分量,然后建立圆方树,每个方点存这个点双内的最小点权 将圆方树树链剖分之后,对于修改操作,将这个点 ...
- 圆方树学习记录及例题
对于一个无向连通图,我们可以通过一些操作使其变成一棵树,然后再在树上操作 这颗树就叫圆方树,具体是怎么样的呢?看下图 这是一个无向连通图 然后找到每一个点双连通分量,并在这个点双里新建一个节点,并且是 ...
- 【蒟蒻の笔记】圆方树初识
圆方树 首先描述一下圆方树: 注:我们把一条边连接两个节点的图也认为是点双连通的. 对于一个无向连通图,对于每个点双连通分量建立一个新的点,新的点作为"方点",原本的点作为&quo ...
- [APIO2018] Duathlon 铁人两项 圆方树,DP
[APIO2018] Duathlon 铁人两项 LG传送门 圆方树+简单DP. 不会圆方树的话可以看看我的另一篇文章. 考虑暴力怎么写,枚举两个点,答案加上两个点之间的点的个数. 看到题面中的一句话 ...
- LOJ.2587.[APIO2018]铁人两项Duathlon(圆方树)
题目链接 LOJ 洛谷P4630 先对这张图建圆方树. 对于S->T这条(些)路径,其对答案的贡献为可能经过的所有点数,那么我们把方点权值设为联通分量的大小,可以直接去求树上路径权值和. 因为两 ...
- [APIO2018]铁人两项——圆方树+树形DP
题目链接: [APIO2018]铁人两项 对于点双连通分量有一个性质:在同一个点双里的三个点$a,b,c$,一定存在一条从$a$到$c$的路径经过$b$且经过的点只被经过一次. 那么我们建出原图的圆方 ...
- [学习笔记]圆方树广义圆方树
引入 偶尔,我们会遇到一些要在无向图/仙人掌上做的问题,这些问题如果在树上就会比较方便,那么我们就开始考虑能不能把原图等效成一棵树,然后就可以方便地乱搞了? 圆方树就是一种将无向图/仙人掌变成树的数据 ...
最新文章
- linux下开启程序崩溃生成core文件开关之ulimit详解
- java-第九章-循环结构进阶-三个班级每班4位同学成绩大于85的算平均分.
- CUDA学习日志:常量内存和纹理内存
- hibernate mysql写入中文乱码
- linux alsa 录音程序,Linux下alsa直接录音代码
- uwsgi: error while loading shared libraries: libicui18n.so.58: cannot open shared object file
- 接口测试用例模板_《测试用例知识大全》----测试用例所有疑问,只需这篇就够了...
- Qt将QString转换成ASCII码
- 进销存系统怎么部署到自己服务器,衡水进销存系统部署
- 【ACWing】998. 起床困难综合症
- 思腾合力-SCM集群下载镜像步骤
- win10打印服务器纸规格没有显示,win10系统打印机添加了自定义的纸张却找不到的操作办法...
- matlab s域极点与零点,S域分析、极点与零点.ppt
- 轻松入门Android直播相关技术 从0搭建直播系统
- 漂亮特殊字体可复制_特殊字体生成器 漂亮特殊字体可复制
- 计算机比赛小组名称和口号,竞赛小组队名和口号
- 怀孕之前营养要充分预备
- 晨枫U盘启动盘制作工具V4.0-安装原版XP的方法
- 掘地三尺搞定 Redis 与 MySQL 数据一致性问题
- zzulioj1123: 最佳校友
热门文章
- java 字符串 哈希值_Java 获取字符串Hash值
- 产品经理vs项目经理?四类PM区别都在这里啦
- c语言迷宫闯关游戏大全,C语言实现迷宫小游戏
- 氮化镓 服务器电源管理系统报价,氮化镓(GaN)技术推动电源管理不断革新
- HTML中abbr标记,html中abbr和acronym标签的区别
- 千人千面算法java实现_推荐算法-recommend_system
- xbox手柄映射_如何在Windows 10中重新映射Xbox One控制器的按钮
- eclipse中项目运行时报错之 Compilation error解决方法
- matlab数字和字符串转换
- 数据库三范式简单理解