自己想了个科技,不知道是不是重复造轮子。
圆方树同时维护割点与割边。
一般来说圆方树只能维护割点。
对于割点的维护是容易的。
那么如何维护割边?
可以考虑映射到点上。
从这角度去想,能发现——割边的两个点一定是能够构成一个点双的。
那么这两个有什么关系?
这两个点被一个圆方树上的一个方点所连接。
那么考虑把这个方点看做割边,就可以用圆方树一些边和割点都要维护的题中。
## 例题
题目是hdu 3896。
简要题意:给定无向图,判断从a到b是否必须经过某点或某边。
#include<bits/stdc++.h>
using namespace std;
int n,m;
const int maxn = 100010;
vector<int> g[maxn],T[500100];
bool tag[500010];
map<pair<int,int>,int> bri;
int dfn[maxn],low[maxn],st[maxn],top,idx,t0t,t1,t2;
void tarjan(int u,int fa){
dfn[u] = low[u] = ++t0t;
st[++top] = u;
for(int v:g[u]){
if(!dfn[v]){
tarjan(v,u);
low[u] = min(low[u],low[v]);
if(dfn[u]<=low[v]){
++idx;
int tmp;
//cout<<"st"<<u<<" ";
if(dfn[u] < low[v]){
bri[{u,v}] = bri[{v,u}] = idx;
}
do{
tmp = st[top--];
T[tmp].push_back(idx);
T[idx].push_back(tmp);
// cout<<tmp<<" ";
}while(tmp != v);
//cout<<endl;
T[idx].push_back(u);
T[u].push_back(idx);
tag[u] = 1;
}
}
else if(v != fa)low[u] = min(low[u],dfn[v]);
}
// cout<<dfn[u]<<" "<<low[u]<<" "<<u<<endl;
}
int f[300010][22],dep[300010];
void dfs(int u,int fa){
//cout<<u<<" "<<fa<<endl;
f[u][0] = fa;
dep[u] = dep[fa]+1;
for(int i = 1;i <= 20;i++){
f[u][i] = f[ f[u][i-1] ][i-1];
}
for(int v:T[u]){
if(v == fa){
continue;
}
dfs(v,u);
}
}
int lca(int u,int v){
if(dep[v]>dep[u])swap(u,v);
//cout<<u<<" "<<v<<endl;
for(int i = 20;i >= 0;i--){
if(dep[f[u][i]] >= dep[v]){
u = f[u][i];
//cout<<u<<endl;
}
}
if(u == v)return u;
for(int i = 20;i >= 0;i--){
if(f[u][i]!= f[v][i]){
u = f[u][i];
v = f[v][i];
//cout<<u<<" "<<v<<endl;
}
}
return f[u][0];
}
map<pair<int,int>,int> mp;
int main(){
//freopen("mission.in","r",stdin);
//freopen("mission.out","w",stdout);
ios::sync_with_stdio(0);
cin>>n>>m;
idx = n;
for(int i = 1;i <= m;i++){
int u,v;
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
for(int i = 1;i <= n;i++){
if(!dfn[i]){
top = 0;
tarjan(i,0);
}
}
dfs(1,0);
// cout<<lca(2,3);
int t;
cin>>t;
int cc = 0;
//cout<<t<<endl;
while(t--){
cc++;
int op;
cin>>op;
if(op == 2){
int x,y,p;
cin>>x>>y>>p;
//cout<<lca(x,p)<<" "<<lca(y,p)<<endl;
if((lca(x,p) == p||lca(y,p) == p)&&dep[p] >= dep[lca(x,y)]){
//cout<<op<<" "<<op<<" "<<op<<" "<<op<<" ";
cout<<"no"<<endl;
}
else{
//cout<<op<<" "<<op<<" "<<op<<" "<<op<<" ";
cout<<"yes"<<endl;
}
}
else{
int x,y,u,v;
cin>>x>>y>>u>>v;
//cout<<lca(x,u)<<" "<<lca(y,u)<<endl;
int p = bri[{u,v}];
if(p == 0){
cout<<"yes"<<endl;
continue;
}
if((lca(x,p) == p||lca(y,p) == p)&&dep[p] >= dep[lca(x,y)]){
//cout<<op<<" "<<op<<" "<<op<<" "<<op<<" ";
cout<<"no"<<endl;
}
else{
//cout<<op<<" "<<op<<" "<<op<<" "<<op<<" ";
cout<<"yes"<<endl;
}
//cout<<"Unknown"<<endl;
}
}
return 0;
}
1208

被折叠的 条评论
为什么被折叠?



