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——圆方树相关推荐

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

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

  2. 【CF487E】Tourists【圆方树】【树链剖分】【multiset】

    题意:给一张 nnn 点 mmm 边的连通无向图,点帯权,qqq 次操作: 修改一个点的权值. 询问两点间所有简单路的最小权值的最小值. n,m,q≤105n,m,q\leq 10^5n,m,q≤10 ...

  3. 广义圆方树+树链剖分+set(Codeforces Round #278 (Div. 1): E. Tourists)

    前置:双联通分量.圆方树.树链剖分 什是是广义圆方树 圆方树是针对于仙人掌建树,而广义圆方树是针对无向图建树,对于一个无向图 无向图中的所有点 → 广义圆方树中的所有圆点 无向图中的一个双联通分量 → ...

  4. CF487E Tourists(圆方树+树链剖分)

    洛谷题目传送门 解题思路 不会圆方树的可以看我的博客圆方树学习记录及例题 首先Tarjan寻找点双连通分量,然后建立圆方树,每个方点存这个点双内的最小点权 将圆方树树链剖分之后,对于修改操作,将这个点 ...

  5. 圆方树学习记录及例题

    对于一个无向连通图,我们可以通过一些操作使其变成一棵树,然后再在树上操作 这颗树就叫圆方树,具体是怎么样的呢?看下图 这是一个无向连通图 然后找到每一个点双连通分量,并在这个点双里新建一个节点,并且是 ...

  6. 【蒟蒻の笔记】圆方树初识

    圆方树 首先描述一下圆方树: 注:我们把一条边连接两个节点的图也认为是点双连通的. 对于一个无向连通图,对于每个点双连通分量建立一个新的点,新的点作为"方点",原本的点作为&quo ...

  7. [APIO2018] Duathlon 铁人两项 圆方树,DP

    [APIO2018] Duathlon 铁人两项 LG传送门 圆方树+简单DP. 不会圆方树的话可以看看我的另一篇文章. 考虑暴力怎么写,枚举两个点,答案加上两个点之间的点的个数. 看到题面中的一句话 ...

  8. LOJ.2587.[APIO2018]铁人两项Duathlon(圆方树)

    题目链接 LOJ 洛谷P4630 先对这张图建圆方树. 对于S->T这条(些)路径,其对答案的贡献为可能经过的所有点数,那么我们把方点权值设为联通分量的大小,可以直接去求树上路径权值和. 因为两 ...

  9. [APIO2018]铁人两项——圆方树+树形DP

    题目链接: [APIO2018]铁人两项 对于点双连通分量有一个性质:在同一个点双里的三个点$a,b,c$,一定存在一条从$a$到$c$的路径经过$b$且经过的点只被经过一次. 那么我们建出原图的圆方 ...

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

    引入 偶尔,我们会遇到一些要在无向图/仙人掌上做的问题,这些问题如果在树上就会比较方便,那么我们就开始考虑能不能把原图等效成一棵树,然后就可以方便地乱搞了? 圆方树就是一种将无向图/仙人掌变成树的数据 ...

最新文章

  1. linux下开启程序崩溃生成core文件开关之ulimit详解
  2. java-第九章-循环结构进阶-三个班级每班4位同学成绩大于85的算平均分.
  3. CUDA学习日志:常量内存和纹理内存
  4. hibernate mysql写入中文乱码
  5. linux alsa 录音程序,Linux下alsa直接录音代码
  6. uwsgi: error while loading shared libraries: libicui18n.so.58: cannot open shared object file
  7. 接口测试用例模板_《测试用例知识大全》----测试用例所有疑问,只需这篇就够了...
  8. Qt将QString转换成ASCII码
  9. 进销存系统怎么部署到自己服务器,衡水进销存系统部署
  10. 【ACWing】998. 起床困难综合症
  11. 思腾合力-SCM集群下载镜像步骤
  12. win10打印服务器纸规格没有显示,win10系统打印机添加了自定义的纸张却找不到的操作办法...
  13. matlab s域极点与零点,S域分析、极点与零点.ppt
  14. 轻松入门Android直播相关技术 从0搭建直播系统
  15. 漂亮特殊字体可复制_特殊字体生成器 漂亮特殊字体可复制
  16. 计算机比赛小组名称和口号,竞赛小组队名和口号
  17. 怀孕之前营养要充分预备
  18. 晨枫U盘启动盘制作工具V4.0-安装原版XP的方法
  19. 掘地三尺搞定 Redis 与 MySQL 数据一致性问题
  20. zzulioj1123: 最佳校友

热门文章

  1. java 字符串 哈希值_Java 获取字符串Hash值
  2. 产品经理vs项目经理?四类PM区别都在这里啦
  3. c语言迷宫闯关游戏大全,C语言实现迷宫小游戏
  4. 氮化镓 服务器电源管理系统报价,氮化镓(GaN)技术推动电源管理不断革新
  5. HTML中abbr标记,html中abbr和acronym标签的区别
  6. 千人千面算法java实现_推荐算法-recommend_system
  7. xbox手柄映射_如何在Windows 10中重新映射Xbox One控制器的按钮
  8. eclipse中项目运行时报错之 Compilation error解决方法
  9. matlab数字和字符串转换
  10. 数据库三范式简单理解