终于学了圆方树啦~\(≧▽≦)/~

感谢y_immortal学长的博客和帮助 把他的博客挂在这里~ 点我传送到巨佬的博客QwQ!

首先我们来介绍一下圆方树能干什么呢qwq

1.将图上问题简化到树上问题

2.一般是路径并

3.资磁修改!

然后我们就可以步入正题来学习圆方树啦~

——超良心圆方树教程!——

这里是一个前缀芝士清单!

1.Tarjan求点双连通分量

2.树链剖分

如果你大体知道这两个东西在干什么 那你看接下来的教程就会非常熟练【大雾

一。圆方树的构造

原图中的点称为原点 新建的点称为方点

对于一个无向图,我们取它所有的极大点双连通分量,把这些点之间的边全部删掉,然后新建一个点与分量中的点连边。

是不是很云里雾里 不着急 我们来画个图【其实是我偷的猫锟的图T^T】

橙色的就是原图圆点 蓝色的就是新建的方点

我们发现 原图中的圆点点双代表的路径 全部都可以被方点表示啦!

也就是说两个点x,y之间的路径并全部都可以被圆点方点表示呢qwq

圆方树可不止这一个性质呢

1.任意两个圆点不会相邻,任意两个方点也不会相邻

2.对于两个方点之间的圆点,是两个点双的公共点,即割点

3.对于两个点x,y,它们的树上简单路径上的圆点都是割点(必经点),路径也是原图x,y之间的路径并

这个过程有一个小细节要注意,就是一个圆点可能会出现在多个点双里,所以在tarjan弹栈的时候不能把当前节点弹出来的qwq

圆方树就讲完啦~ 是不是很简单!接下来就可以刚题啦/xyx

————一道例题————

CF487E Tourists

没想到4年前就已经有圆方树了呢qwq

题意:给定一张无向图,求两点之间路径最小值的最小值,带修。

两点之间路径并!圆方树!

对于这个题,我们可以轻松地建出模型。

对原图建立圆方树,查询树上两个点之间的路径最小值。

每个方点维护它所连接的所有圆点的权值。

但是问题来了,如果出现菊花图,一个圆点的修改可能会影响到O(n)级别的方点

然后就萎啦QAQ

我们对这个东西进行优化 对于一个方点 我们可以开一个multiset维护它第一层儿子的权值,然后每次修改一个圆点,只会影响到一个方点,这样的话时间复杂度是O(nlg^2n)可以接受的。

然后你就写呀写。交上去。WA了!!!你正准备喷笔者。不要着急好不好!我们还有一个小问题没处理呢。

我们发现原先一个方点维护的是它连接的所有圆点,但是我们现在维护的是它的儿子的权值。这之间是不是有一点小出入呢。

没错,当x,y的lca为一个方点时,我们少维护了一个点,就是方点上方的圆点,这个圆点也是属于这个点双的,也是可以被经过的,所以,你只需要加一个小细节,对于LCA时方点的,答案还需要和方点上方的圆点取最小值。

这样就做完啦~

码量还好呢qwq

放代码啦。

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<cmath>
  5. #include<stack>
  6. #include<set>
  7. #define inf 2002122500
  8. #define ll long long
  9. #define mxn 100010
  10. #define ls x<<1
  11. #define rs x<<1|1
  12. using namespace std;
  13. struct edge{int to,lt;}e[mxn<<2],p[mxn<<1];
  14. int in[mxn<<1],ip[mxn],cnt,cnp,v[mxn<<1],n,m;
  15. int dfn[mxn<<1],low[mxn<<1],tot,dep[mxn<<1];
  16. int son[mxn<<1],sz[mxn<<1],top[mxn<<1],fa[mxn<<1],xl[mxn<<1];
  17. int num;stack<int> st;
  18. multiset<int> sq[mxn];
  19. struct SegTree
  20. {
  21. int mn[mxn<<4];
  22. void pushup(int x){mn[x]=min(mn[ls],mn[rs]);}
  23. void build(int x,int l,int r)
  24. {
  25. if(l==r){mn[x]=v[xl[l]];return;}
  26. int mid=l+r>>1;
  27. build(ls,l,mid);
  28. build(rs,mid+1,r);
  29. pushup(x);
  30. }
  31. void modify(int x,int l,int r,int d,int val)
  32. {
  33. if(l==r){mn[x]=val;return;}
  34. int mid=l+r>>1;
  35. if(d<=mid) modify(ls,l,mid,d,val);
  36. else modify(rs,mid+1,r,d,val);
  37. pushup(x);
  38. }
  39. int query(int x,int l,int r,int LL,int RR)
  40. {
  41. if(l>=LL&&RR>=r) return mn[x];
  42. int mid=l+r>>1,ans=inf;
  43. if(LL<=mid) ans=min(ans,query(ls,l,mid,LL,RR));
  44. if(RR>mid) ans=min(ans,query(rs,mid+1,r,LL,RR));
  45. return ans;
  46. }
  47. }T;
  48. void app(int x,int y)
  49. {
  50. p[++cnp].to=y;p[cnp].lt=ip[x];ip[x]=cnp;
  51. p[++cnp].to=x;p[cnp].lt=ip[y];ip[y]=cnp;
  52. }
  53. void add(int x,int y)
  54. {
  55. e[++cnt].to=y;e[cnt].lt=in[x];in[x]=cnt;
  56. e[++cnt].to=x;e[cnt].lt=in[y];in[y]=cnt;
  57. }
  58. void tarjan(int x,int ff)
  59. {
  60. dfn[x]=low[x]=++tot;st.push(x);
  61. for(int i=ip[x];i;i=p[i].lt)
  62. {
  63. int y=p[i].to;if(y==ff) continue;
  64. if(!dfn[y])
  65. {
  66. tarjan(y,x);
  67. low[x]=min(low[y],low[x]);
  68. if(low[y]>=dfn[x])
  69. {
  70. int cur;++num;
  71. add(num,x);
  72. do
  73. {
  74. cur=st.top();st.pop();
  75. add(num,cur);
  76. }while(cur!=y);
  77. }
  78. }
  79. else low[x]=min(low[x],dfn[y]);
  80. }
  81. }
  82. void dfs(int x)
  83. {
  84. sz[x]=1;
  85. for(int i=in[x];i;i=e[i].lt)
  86. {
  87. int y=e[i].to;if(y==fa[x]) continue;
  88. dep[y]=dep[x]+1;fa[y]=x;dfs(y);sz[x]+=sz[y];
  89. if(sz[y]>sz[son[x]]) son[x]=y;
  90. if(x>n) sq[x-n].insert(v[y]);
  91. }
  92. if(x>n) v[x]=*sq[x-n].begin();
  93. }
  94. void dfs2(int x,int tt)
  95. {
  96. top[x]=tt;dfn[x]=++tot;xl[tot]=x;
  97. if(!son[x]) return;
  98. dfs2(son[x],tt);
  99. for(int i=in[x];i;i=e[i].lt)
  100. {
  101. int y=e[i].to;
  102. if(y==fa[x]||y==son[x]) continue;
  103. dfs2(y,y);
  104. }
  105. }
  106. int ask(int x,int y)
  107. {
  108. int ans=inf;
  109. while(top[x]!=top[y])
  110. {
  111. if(dep[top[y]]>dep[top[x]]) swap(x,y);
  112. ans=min(ans,T.query(1,1,num,dfn[top[x]],dfn[x]));
  113. x=fa[top[x]];
  114. }
  115. if(dep[x]>dep[y]) swap(x,y);
  116. //printf("QWQ");
  117. //printf("%d %d %d %d\n",x,y,dfn[x],dfn[y]);
  118. ans=min(ans,T.query(1,1,num,dfn[x],dfn[y]));
  119. if(x>n) ans=min(ans,v[fa[x]]);
  120. return ans;
  121. }
  122. void change(int x,int val)
  123. {
  124. if(fa[x]) sq[fa[x]-n].erase(v[x]),sq[fa[x]-n].insert(val),v[fa[x]]=*sq[fa[x]-n].begin();
  125. v[x]=val;T.modify(1,1,num,dfn[x],v[x]);
  126. if(fa[x]) T.modify(1,1,num,dfn[fa[x]],v[fa[x]]);
  127. }
  128. int main()
  129. {
  130. int x,y,q;char ch[5];
  131. scanf("%d%d%d",&n,&m,&q);num=n;
  132. for(int i=1;i<=n;i++) scanf("%d",&v[i]);
  133. for(int i=1;i<=m;i++)
  134. {
  135. scanf("%d%d",&x,&y);
  136. app(x,y);
  137. }
  138. for(int i=1;i<=n;i++)
  139. if(!dfn[i]) tarjan(i,i);
  140. tot=0;
  141. for(int i=1;i<=n;i++)
  142. if(!dep[i]) dep[i]=1,dfs(i),dfs2(i,i);
  143. T.build(1,1,num);
  144. for(int i=1;i<=q;i++)
  145. {
  146. scanf("%s%d%d",ch,&x,&y);
  147. if(ch[0]=='C') change(x,y);
  148. else printf("%d\n",ask(x,y));
  149. }
  150. return 0;
  151. }

完结撒花ヾ(o◕∀◕)ノヾ

【学习笔记】圆方树(CF487E Tourists)的更多相关文章

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

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

  2. 仙人掌&圆方树学习笔记

    仙人掌&圆方树学习笔记 1.仙人掌 圆方树用来干啥? --处理仙人掌的问题. 仙人掌是啥? (图片来自于\(BZOJ1023\)) --也就是任意一条边只会出现在一个环里面. 当然,如果你的图 ...

  3. 【CF487E】Tourists(圆方树)

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

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

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

  5. CF487E Tourists 【圆方树 + 树剖 + 堆】

    题目链接 CF487E 题解 圆方树 + 树剖 裸题 建好圆方树维护路径上最小值即可 方点的值为其儿子的最小值,这个用堆维护 为什么只维护儿子?因为这样修改点的时候就只需要修改其父亲的堆 这样充分利用 ...

  6. Note -「圆方树」学习笔记

    目录 圆方树的定义 圆方树的构造 实现 细节 圆方树的运用 「BZOJ 3331」压力 「洛谷 P4320」道路相遇 「APIO 2018」「洛谷 P4630」铁人两项 「CF 487E」Touris ...

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

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

  8. 圆方树&广义圆方树[学习笔记]

    仙人掌 圆方树是用来解决仙人掌图的问题的,那什么是仙人掌图呢? 如图,不存在边同时属于多个环的无向连通图是一棵仙人掌 圆方树 定义 原先的仙人掌图,通过一些奇妙的方法,可以转化为一棵由圆点,方点和树边 ...

  9. CF487E Tourists【圆方树+tarjan+multiset+树剖+线段树】

    圆方树不仅能解决仙人掌问题(虽然我仙人掌问题也没用过圆方树都是瞎搞过去的),还可以解决一般图的问题 一般图问题在于缩完环不是一棵树,所以就缩点双(包括双向边) 每个方点存他所在点双内除根以外的点的最小 ...

随机推荐

  1. apache如何发布地图服务

    svg jpg Tomcat和apache是什么关系呢?:https://www.cnblogs.com/zangdalei/p/8057325.html geoserver又是怎么来的呢? Tomc ...

  2. HelloServlet类继承HttpServlet利用HttpServletResponse对象

    HelloServlet类继承HttpServlet利用HttpServletResponse对象 HelloServlet类的doGet()方法先得到username请求参数,对其进行中文字符编码转 ...

  3. mysql之存储过程基础篇

    1.  创建/使用数据库 mysql> create database me; mysql> use me; 2.  创建表 mysql> create table Stu(Sno ...

  4. 结合process进程,实现进程之间的通讯Queue,稍微复杂的运用

    #在父进程中创建两个子进程,一个往Queue写数据,一个从Queue里读数据 from multiprocessing import Queue,Process import time,random ...

  5. Learning OSG programing---osgAnimation(1)

    osg::AnimationPath* createAnimationPath(const osg::Vec3& center,float radius,double looptime) { ...

  6. flex布局相关用法

    /* pages/classic/classic.wxss */ .chunk { /* 行内元素可设置但是设置了flex,无效了 *//* display: inline-block; */ wid ...

  7. stl应用(map)或字典树(有点东西)

    M - Violet Snow Gym - 101350M Every year, an elephant qualifies to the Arab Collegiate Programming C ...

  8. traceroute学习

    之前只知道ping telnet命令,后面学习了traceroute命令 ping最常用的,看是否可以ping通ip,查看网络是否可达 telnet探测端口是否通,telnet ip port tra ...

  9. MySQL对字段新增自增序列

    现在有这样的场景,我们的数据库类型是MySQL,表是从其他库拿过来的,约束和索引都没迁移.现在希望增加一个自增序列. 且自增序列是从当前最大自增ID开始的,下面就是这样一个过程的演示. mysql&g ...

  10. Mata标签,og标签

    一.Mata标签 meta是用来在HTML文档中模拟HTTP协议的响应头报文,meta 标签用于网页的<head>与</head>中.meta 的属性有两种:name和http ...