UOJ#30/Codeforces 487E Tourists 点双连通分量,Tarjan,圆方树,树链剖分,线段树
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ30.html
题目传送门 - UOJ#30
题意
uoj写的很简洁、清晰,这里就不抄一遍了。
题解
首先建出圆方树。接下来,我们称"圆点"为原来有的点,"方点"为新增的点。
然后先只考虑在线询问如何做。
——把方点的值设置成所有与他连边的圆点的权值的最小值,直接在圆方树上树链剖分再套个线段树支持一下区间询问即可。
然后会发现这样做支持不了修改操作。
——直接来个菊花图不断修改根节点就GG了。
于是我们考虑进一步想办法。
我们把方点的值重新定义成“在圆方树上,该点的儿子的权值的最小值”。那么,在询问的时候,其他都一样,但是如果 lca 为方点,那么加上其 fa 对 min 的贡献即可。
时间复杂度 $O(n\log ^2 n )$ 。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL read(){
LL x=0,f=1;
char ch=getchar();
while (!isdigit(ch)&&ch!='-')
ch=getchar();
if (ch=='-')
f=-1,ch=getchar();
while (isdigit(ch))
x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return x*f;
}
const int N=200005,INF=1.1e9;
int pr[N],dfn[N],low[N],st[N],Time,top,tot;
multiset <int> Mins[N];
vector <int> G[N],g[N];
void Tarjan(int x){
low[x]=dfn[x]=++Time,st[++top]=x;
for (auto y : G[x])
if (!dfn[y]){
Tarjan(y);
low[x]=min(low[x],low[y]);
if (low[y]>=dfn[x]){
tot++;
g[x].push_back(tot);
g[tot].push_back(x);
int z;
do {
z=st[top--];
g[z].push_back(tot);
g[tot].push_back(z);
} while (z!=y);
}
}
else
low[x]=min(low[x],dfn[y]);
}
namespace sp{
int n,outn;
int fa[N],son[N],size[N],depth[N],top[N],p[N],ap[N],cnp=0,val[N];
void dfs(int x,int pre,int d){
size[x]=1,fa[x]=pre,son[x]=-1,depth[x]=d;
for (auto y : g[x])
if (y!=pre){
dfs(y,x,d+1);
size[x]+=size[y];
if (son[x]==-1||size[y]>size[son[x]])
son[x]=y;
}
}
void Get_Top(int x,int tp){
top[x]=tp;
ap[p[x]=++cnp]=x;
if (son[x]==-1)
return;
Get_Top(son[x],tp);
for (auto y : g[x])
if (y!=fa[x]&&y!=son[x])
Get_Top(y,y);
}
int Min[N<<2];
void build(int rt,int L,int R){
if (L==R)
return (void)(Min[rt]=val[ap[L]]);
int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
build(ls,L,mid);
build(rs,mid+1,R);
Min[rt]=min(Min[ls],Min[rs]);
}
int query(int rt,int L,int R,int xL,int xR){
if (xL>xR||L>xR||R<xL)
return INF;
if (xL<=L&&R<=xR)
return Min[rt];
int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
return min(query(ls,L,mid,xL,xR),query(rs,mid+1,R,xL,xR));
}
void update(int rt,int L,int R,int x,int d){
if (L==R)
return (void)(Min[rt]=d);
int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
if (x<=mid)
update(ls,L,mid,x,d);
else
update(rs,mid+1,R,x,d);
Min[rt]=min(Min[ls],Min[rs]);
}
int query(int a,int b){
int f1=top[a],f2=top[b],ans=INF;
while (f1!=f2){
if (depth[f1]<depth[f2])
swap(f1,f2),swap(a,b);
ans=min(ans,query(1,1,n,p[f1],p[a]));
a=fa[f1],f1=top[a];
}
if (depth[a]>depth[b])
swap(a,b);
if (a>outn&&fa[a]!=0)
ans=min(ans,query(1,1,n,p[fa[a]],p[fa[a]]));
return min(ans,query(1,1,n,p[a],p[b]));
}
}
int main(){
int n=tot=read(),m=read(),q=read();
for (int i=1;i<=n;i++)
pr[i]=read();
for (int i=1;i<=m;i++){
int a=read(),b=read();
G[a].push_back(b);
G[b].push_back(a);
}
Tarjan(1);
sp :: dfs(1,0,0);
sp :: Get_Top(1,1);
for (int i=n+1;i<=tot;i++)
Mins[i].insert(INF);
for (int i=1;i<=n;i++)
Mins[sp :: fa[i]].insert(pr[i]);
for (int i=1;i<=n;i++)
sp :: val[i]=pr[i];
for (int i=n+1;i<=tot;i++)
sp :: val[i]=*Mins[i].begin();
sp :: build(1,1,sp :: n=tot);
sp :: outn=n;
while (q--){
char s[10];
scanf("%s",s);
int x=read(),y=read();
if (s[0]=='A')
printf("%d\n",sp :: query(x,y));
else {
int f=sp :: fa[x];
if (f){
Mins[f].erase(Mins[f].find(pr[x]));
Mins[f].insert(pr[x]=y);
sp :: update(1,1,sp :: n,sp :: p[f],*Mins[f].begin());
}
sp :: update(1,1,sp :: n,sp :: p[x],y);
}
}
return 0;
}
UOJ#30/Codeforces 487E Tourists 点双连通分量,Tarjan,圆方树,树链剖分,线段树的更多相关文章
- HDU  2460 Network(双连通+树链剖分+线段树)
		HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ... 
- Water Tree CodeForces 343D 树链剖分+线段树
		Water Tree CodeForces 343D 树链剖分+线段树 题意 给定一棵n个n-1条边的树,起初所有节点权值为0. 然后m个操作, 1 x:把x为根的子树的点的权值修改为1: 2 x:把 ... 
- Educational Codeforces Round 3 E. Minimum spanning tree for each edge 最小生成树+树链剖分+线段树
		E. Minimum spanning tree for each edge time limit per test 2 seconds memory limit per test 256 megab ... 
- Codeforces Round #200 (Div. 1)  D. Water Tree 树链剖分+线段树
		D. Water Tree time limit per test 4 seconds memory limit per test 256 megabytes input standard input ... 
- Codeforces 487E Tourists [广义圆方树,树链剖分,线段树]
		洛谷 Codeforces 思路 首先要莫名其妙地想到圆方树. 建起圆方树后,令方点的权值是双联通分量中的最小值,那么\((u,v)\)的答案就是路径\((u,v)\)上的最小值. 然而这题还有修改, ... 
- CF487 E. Tourists [点双连通分量 树链剖分 割点]
		E. Tourists 题意: 无向连通图 C a w: 表示 a 城市的纪念品售价变成 w. A a b: 表示有一个游客要从 a 城市到 b 城市,你要回答在所有他的旅行路径中最低售价的最低可能值 ... 
- Simple Cycles Edges CodeForces - 962F(点双连通分量)
		题意: 求出简单环的所有边,简单环即为边在一个环内 解析: 求出点双连通分量,如果一个连通分量的点数和边数相等,则为一个简单环 点双连通分量 任意两个点都至少存在两条点不重复的路径 即任意两条边都 ... 
- codeforces 487E Tourists
		如果不是uoj上有的话(听说这是China Round),我有可能就错过这道题目了(这是我有史以来为oi写的最长的代码,用了我一天TAT!). 题目 传送门. 一个连通无向图,点上有权,支持两种操作: ... 
- 点/边 双连通分量---Tarjan算法
		运用Tarjan算法,求解图的点/边双连通分量. 1.点双连通分量[块] 割点可以存在多个块中,每个块包含当前节点u,分量以边的形式输出比较有意义. typedef struct{ //栈结点结构 保 ... 
随机推荐
- POJ 1659
			题意: 给你一个数列, 判断是否可以构成一个图, 可以则输出 构成图的一种方式 构图根据 Havel-Hakimi定理来构图 (在排序的时候注意 节点下标会变化, 故用结构体) #include< ... 
- appium+java (六) 手机chrome浏览器操作
			一.前言 早之前写过一段时间的appium for native app(即原生app脚本),但尴尬的是从未写过类似的文章,后期有时间我会陆续接着写,近一阶段有时间又把appium捡起来了,由于公司产 ... 
- Solidity基础
			方法和匿名方法: funcion name(<parameter types>){public|private|internal|external}[constant][payable][ ... 
- windows连接服务端的域名正常,linux却不通,(针对于负载均衡后端节点设置)
			1.初步判断不是网络上的,因为windows主机访问正常, 2.修改客户端linux主机 net.ipv4.tcp_tw_recycle=0,测试是否正常,(服务器当连接数达到一定量之后,会执行rec ... 
- css之坑
			1.background-size要放在background后边才会生效. 2.隐藏滚动条,内容可以滑动 body::-webkit-scrollbar { display: none /* 隐藏滚动 ... 
- Vue中的render函数随笔
			使用vue-cli创建项目后,再main.js里面有这样一段代码: new Vue({ render:h => h(App) }).$mount('#app') render函数是渲染一个视图, ... 
- Confluence 6 通过 SSL 或 HTTPS 运行 - 为 HTTPS 修改你的 Confluence 基础 URL
			在你的浏览器中,进入 > 基本配置(General Configuration). 单击 编辑(Edit). 修改服务器的基础 URL 为 HTTPS.请参考文档 configuring t ... 
- Confluence 6 管理员联系表单的后台配置界面
			管理员联系表单的后台配置界面截图和配置. 对输入的数据进行编辑和选择是否启用发送电子邮件给管理员 https://www.cwiki.us/display/CONFLUENCEWIKI/Configu ... 
- MySql在windows上的安装
			知乎安装教程 csdn安装教程 一.官网下载 ZIP Archive 内的软件包,mysql-xxx-win64.zip. 二.新建 MySQL 文件夹,解压缩下载包,进入文件夹(mysql-8.0. ... 
- CF451E
			一道不错的题,对排列组合能力的要求较高 题意:给定s个相同的小球放在n个不同的盒子里,可以不放,每个盒子有一个放的上限,求一共有多少种放法 解析:首先考虑没有上限的情况,这里比较好解决,采用隔板法,可 ... 
