ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

圆方树

2022-07-06 20:06:30  阅读:130  来源: 互联网

标签:cnt int dfn low 圆方树 col


目录

圆方树

前言

众所周知,树往往有着许多非常好的性质

圆方树就是一种把一个图变成一棵树的方式

定义

我们一般在无向图上使用圆方树

先介绍点双连通分量

一个点双连通图的定义:图中任意两点之间都至少有两条不同的路径可互相抵达

一个点双连通分量是一个极大点双连通图

在圆方树中,每个原图中的点对应一个圆点,每个点双对应方点,每个点(圆点)和其对应的点双(方点)连边

上图就分别展示了原图,点双以及对应的圆方树

显然,圆点不和圆点连,方点不和方点连

我们可以在方点处维护有关点双内多条路径的信息

如何建树

首先我们需要跑一遍 \(tarjan\) 找出每个点双,然后将每个点双代表的方点和点双内的点代表的圆点连边,就建出了一棵圆方树

如下:

inline void tarjan(int x){
	dfn[x]=low[x]=++cnt;
	S.push(x);
	for(auto y:G[x]){
		if(!dfn[y]){
			tarjan(y);
			low[x]=min(low[x],low[y]);
			if(low[y]==dfn[x]){
				++col_cnt;
				for(int j=0;j!=y;S.pop()){
					j=S.top();
					H[col_cnt].pb(j);
					H[j].pb(col_cnt);
				}
				H[col_cnt].pb(x);
				H[x].pb(col_cnt);
			}
		}
		else low[x]=min(low[x],dfn[y]);
	}
}

习题

CF487E tourists

题意

给定一张图(保证连通),每个点有点权。

现在有两种操作:

  • C a w:把 \(a\) 的点权改为 \(w\)

  • A a b:询问从 \(a\)到 \(b\) 的所有简单路径(不经过重复点)中,点权最小的点的点权。

思路

在图上搞树剖的操作?

考虑先把图变成一棵树

采用圆方树,然后搞树剖

容易想到把每个方点的权值设为周围所有圆点的最小的权值,搞个 \(multiset\) 维护一下

然而暴力修改会被卡

利用圆方树是一棵树的性质

我们把每个方点的权值设为其所有儿子节点的最小值,对于每一个方点开一个 \(multiset\) 维护最值

这样就可以保证复杂度

#include<bits/stdc++.h>
using namespace std;

#define pb push_back
#define lsp p<<1
#define rsp p<<1|1
#define size pajo
#define int long long

const int N=3e5+5;
const int inf=1e9+5;

inline int read(){
	int x=0,f=1;
	char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(isdigit(ch)){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}

int n,m,q,cnt,col_cnt;
int w[N];
int low[N],dfn[N];
int dep[N],f[N],size[N],son[N];
int top[N],val[N];
stack <int> S;
multiset <int> s[N];
vector <int> G[N],H[N];

struct node{
	int l,r;
	int mn;
}t[N<<2];

node operator + (node l,node r){
	return (node){l.l,r.r,min(l.mn,r.mn)};
}

inline void build(int p,int l,int r){
	if(l==r){
		t[p]={l,r,val[l]};
		return;
	}
	int mid=l+r>>1;
	build(lsp,l,mid);
	build(rsp,mid+1,r);
	t[p]=t[lsp]+t[rsp];
}

inline void update(int p,int x,int k){
	if(t[p].l==t[p].r&&t[p].l==x){
		t[p].mn=k;
		return;
	}
	int mid=t[p].l+t[p].r>>1;
	if(x<=mid) update(lsp,x,k);
	else update(rsp,x,k);
	t[p]=t[lsp]+t[rsp];
}

inline node query(int p,int l,int r){
	if(l<=t[p].l&&t[p].r<=r) return t[p];
	node res={0,0,inf};
	int mid=t[p].l+t[p].r>>1;
	if(l<=mid) res=res+query(lsp,l,r);
	if(mid<r) res=res+query(rsp,l,r);
	return res;
}

inline void dfs1(int x,int fa){
	dep[x]=dep[fa]+1,size[x]=1,f[x]=fa;
	int maxson=-1;
	for(auto y:H[x]){
		if(y==fa) continue;
		dfs1(y,x);
		size[x]+=size[y];
		if(size[y]>maxson) maxson=size[y],son[x]=y;
	}
}

inline void dfs2(int x,int tp){
	dfn[x]=++cnt,top[x]=tp,val[cnt]=w[x];
	if(!son[x]) return;
	dfs2(son[x],tp);
	for(auto y:H[x]){
		if(y==f[x]||y==son[x]) continue;
		dfs2(y,y);
	}
}

inline int Q(int x,int y){
	node res=(node){0,0,inf};
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		res=res+query(1,dfn[top[x]],dfn[x]);
		x=f[top[x]];
	}
	if(dep[x]>dep[y]) swap(x,y);
	res=res+query(1,dfn[x],dfn[y]);
	if(x>n)
		res.mn=min(res.mn,w[f[x]]);
	return res.mn;
}

inline void tarjan(int x){
	dfn[x]=low[x]=++cnt;
	S.push(x);
	for(auto y:G[x]){
		if(!dfn[y]){
			tarjan(y);
			low[x]=min(low[x],low[y]);
			if(low[y]==dfn[x]){
				++col_cnt;
				for(int j=0;j!=y;S.pop()){
					j=S.top();
					H[col_cnt].pb(j);
					H[j].pb(col_cnt);
				}
				H[col_cnt].pb(x);
				H[x].pb(col_cnt);
			}
		}
		else low[x]=min(low[x],dfn[y]);
	}
}

signed main(){
	n=read(),m=read(),q=read();
	col_cnt=n;
	for(int i=1;i<=n;++i) w[i]=read();
	for(int i=1;i<=m;++i){
		int x=read(),y=read();
		G[x].pb(y);
		G[y].pb(x);
	}
	tarjan(1);
	memset(dfn,0,sizeof(dfn));
	cnt=0;
	dfs1(1,0);
	for(int i=1;i<=n;++i)
		if(f[i])
			s[f[i]].insert(w[i]);
	for(int i=n+1;i<=col_cnt;++i)
		w[i]=*s[i].begin();
	dfs2(1,1);
	build(1,1,col_cnt);
	while(q--){
		char ch;
		cin>>ch;
		int x=read(),y=read();
		if(ch=='A') cout<<Q(x,y)<<endl;
		else{
			update(1,dfn[x],y);
			if(!f[x]){
				w[x]=y;
				continue;
			}
			s[f[x]].erase(s[f[x]].lower_bound(w[x]));
			s[f[x]].insert(y);
			if(w[f[x]]!=*s[f[x]].begin()){
				w[f[x]]=*s[f[x]].begin();
				update(1,dfn[f[x]],w[f[x]]);
			}
			w[x]=y;
		}
	}
}

标签:cnt,int,dfn,low,圆方树,col
来源: https://www.cnblogs.com/into-qwq/p/16452284.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有