【图论】浅谈基环树 11.23学习总结

发布时间 2023-11-24 01:40:31作者: 木易meow

开篇碎碎念

今天是继续图论的一天!所以就基环树启动!耶!!!下周就可以回家家啦,开心!!!

什么是基环树

简单来说就是一个树+一个环。在原本一棵树的基础上,添加了一个边,从而形成了一个环。
image

特殊的基环树

  • 内向树:每个点仅有一个入边
    image

  • 外向树:每个点仅有一个出边
    image

常见处理

  • 化环为链 然后对于环进行计算
  • 分类讨论 按照结果是否含有环

如何找环

拓扑排序:最后剩下的点都在环上

题目:P8943

#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e5+10;
bool cir[MAXN];//是否在圆上 
vector<int>e[MAXN];//存图 
int tot[MAXN];//记录入边 
int dir[MAXN];//环外到环的距离 
int hdir[MAXN];//环上点的距离 
int com[MAXN];//进入环的位置 
int cnt=0;
int n;
void topu(){
	queue<int>q;
	for(int i=1;i<=n;i++){
		if(tot[i]==1){
			q.push(i);
		}
	}
	int fr;
	while(!q.empty()){
		fr=q.front();
		q.pop();
		cir[fr]=0;
		for(auto i:e[fr]){
			if(cir[i]==0)continue;
			tot[i]--;
			if(tot[i]==1){
				q.push(i);
			}
		}
	}
}
int vis[MAXN];
void dfs(int x){//对环上的点标序号 
	hdir[x]=++cnt;
	vis[x]=1;
	for(auto i:e[x]){
		if(!cir[i])continue;
		if(vis[i])continue;
		dfs(i);
	}
}
void hdis(){//找出第一个在环上的点 
	int st;
	for(int i=1;i<=n;i++){
		if(cir[i]==1){
			st=i;
			break;
		}
	}
	dfs(st);
}
int dis=0;
int viss[MAXN];
void dfss(int x,int w){
	com[x]=w;
	viss[x]=1;
	for(auto i:e[x]){
		if(cir[i])continue;
		if(viss[i])continue;
		dir[i]=dir[x]+1;
		dfss(i,w);
	}
} 
void wdfs(){//找到所有在环上的点,遍历子树 
	for(int i=1;i<=n;i++){
		if(cir[i]){
			dis=0;
			dfss(i,i);
		}
	}
}
int main(){
	int q;
	cin>>n>>q;
	int u,v;
	for(int i=1;i<=n;i++){
		cir[i]=1;
	}
	for(int i=1;i<=n;i++){
		cin>>u>>v;
		e[u].push_back(v);
		e[v].push_back(u);
		tot[v]++;tot[u]++;
	}
	topu();
	hdis();
	wdfs();
	while(q--){
		cin>>u>>v;
		int a1=dir[u];
		int aw=com[u];
		int b1=dir[v];
		int bw=com[v];
		if(hdir[aw]<hdir[bw])swap(aw,bw);
		int dis=min(hdir[aw]-hdir[bw],cnt-hdir[aw]+hdir[bw]);
//		cout<<a1<<' '<<aw<<' '<<b1<<' '<<bw<<' '<<dis<<endl;
		if(dis+b1<=a1)cout<<"Deception"<<endl;
		else cout<<"Survive"<<endl;
	}
}