首页 > 其他分享 >基环树

基环树

时间:2024-07-22 11:07:06浏览次数:5  
标签:fa int long 基环树 断点 dp

基环树

一棵树多了一条边。。。就变成了基环树

首先把这个环找出来,对于这个环,断掉一条边就变成树了,固定一个端点跑树形 dp。

城市环路

很板子,没坑点。找环可以用并查集,不用知道具体有哪些点。

我们只需要找出其中一条边的两个端点作为断点就好了。

for(int i=1;i<=n;i++)
{
	int x,y; scanf("%d%d",&x,&y); x++,y++;
	if(find(x)!=find(y)) add(x,y),add(y,x),fa[find(x)]=y;
	else r1=x,r2=y;
}

每一个点可以选或不选,注意我们强制锁定断点时只能锁定它不选。

否则因为两个断点间没有连边,无法判断会不会两个断点都选的情况。

dp 是裸的树上 dp。

code
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
#define LL long long
int n,p[N],r1,r2;
long double k,ans;
int head[N],tot;
struct E {int u,v;} e[N<<1];
void add(int u,int v) {e[++tot]={head[u],v}; head[u]=tot;}
int fa[N];
LL f[N][2];
int find(int x)
{
	if(fa[x]!=x) fa[x]=find(fa[x]);
	return fa[x];
}
void dp(int u,int fa)
{
	f[u][0]=0,f[u][1]=p[u];
	for(int i=head[u];i;i=e[i].u)
	{
		int v=e[i].v;
		if(v==fa) continue;
		dp(v,u);
		f[u][0]+=max(f[v][0],f[v][1]);
		f[u][1]+=f[v][0];
	}
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&p[i]),fa[i]=i;
	for(int i=1;i<=n;i++)
	{
		int x,y; scanf("%d%d",&x,&y); x++,y++;
		if(find(x)!=find(y)) add(x,y),add(y,x),fa[find(x)]=y;
		else r1=x,r2=y;
	}
	scanf("%Lf",&k);
	dp(r1,0); ans=max(k*f[r1][0],ans);//只能限制不要,如果强制要的话会和 r2 冲突
	dp(r2,0); ans=max(k*f[r2][0],ans);
	printf("%.1Lf\n",ans);
	return 0;
}

骑士

双倍经验???

坑点多,直接把上一道题的板子推翻了。

  1. 会有森林,dp 要覆盖所有连通块。

  2. 会有重边,不能用并查集只判点,需要建有向图找环。

我们在每一个连通图各找一次环,记录父亲,建外向图(都背向环),这样每次跳父亲一定会终止在环里。

void work(int u)
{
	while(!vs[u]) vs[u]=1,u=fa[u];//一定会跳到环上一个点,手摸一下 
	dfs(u,u);
	LL res=f[u][0];
	dfs(fa[u],fa[u]);
	ans+=max(res,f[fa[u]][0]);
}

然后 dp 连通块,dp 过程中记录那个开始的父亲,因为有向图,只需要不等于这个父亲就一直遍历。

code
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+5;
#define LL long long 
int n,fa[N],a[N];
LL f[N][2],ans;
int head[N],tot;
struct E {int u,v;} e[N<<1];
void add(int u,int v) {e[++tot]={head[u],v}; head[u]=tot;}
bool vs[N];
void dfs(int u,int x)//有向图,不用判父亲,判环接头处 
{
	vs[u]=1; f[u][0]=0,f[u][1]=a[u];
	for(int i=head[u];i;i=e[i].u)
	{
		int v=e[i].v;
		if(v!=x)
		{
			dfs(v,x);
			f[u][0]+=max(f[v][0],f[v][1]);
			f[u][1]+=f[v][0];			
		}
	}
}
void work(int u)
{
	while(!vs[u]) vs[u]=1,u=fa[u];//一定会跳到环上一个点,手摸一下 
	dfs(u,u);
	LL res=f[u][0];
	dfs(fa[u],fa[u]);
	ans+=max(res,f[fa[u]][0]);
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld%d",&a[i],&fa[i]);//会有重边,不能用并查集判点 
		add(fa[i],i);
	}
	for(int i=1;i<=n;i++) if(!vs[i]) work(i);
	printf("%lld\n",ans);
	return 0;
}

标签:fa,int,long,基环树,断点,dp
From: https://www.cnblogs.com/ppllxx-9G/p/18315660

相关文章

  • 基环树
    定义(图片来自这篇文章)基环树:有\(n\)个点\(n\)条边的连通图外向树:每个点出度为\(1\)内向树:每个点入度为\(1\)找环\(dfs\)拓扑排序一般处理方法因题而异,一般有两种常用的第一种是先断掉环边,把环上点当作根,处理每一棵子树,再在环上处理,可能需要......
  • 基环树
    基环树定义在树形结构中添加一条边形成的图。分类无向图基环树内向基环树,每个点的出度为1。外向基环树,每个点的入度为1。找环:方法1:无向图基环树找环。拓扑排序,去掉环以外的点,剩下的就是一个那个环。方法2:有向图和无向图均适用。原理:在搜索树中检查一个点\(x\)的......
  • 基环树
    在树形结构中添加1条边形成的图分类:1.无向图基环树2.内向基环树,每个点出度为1的情况一棵内向基环树3.外向基环树,每个点入度为1的情况找环方法1:无向基环树找环1.统计节点的度数deg[i]2.将度数为1的点入队3.循环从队首取出节点x并将x的邻接点y度数减14.若deg[y]==1......
  • 基环树和笛卡尔树
    基环树就是比平常的树多一条边,有\(n\)条边,也就有一个环在里面。基本思想就是断环,跑树形\(dp\),或者用拓扑排序判环去跑环形\(dp\)。树的直径今天才了解到的,用两遍\(dfs\)跑。首先第一遍找到离根节点最远的节点\(u_1\),然后再从\(u_1\)找到离它最远的节点\(u_2\),那么......
  • 基环树和笛卡尔树
    1.基环树定义:有\(n\)个点和\(n\)条边的图,就是给树连了一条边,此时图中恰好只有一个环解决这类问题时,通常断环,变成普通的树的问题,然后再特殊处理环P2607[ZJOI2008]骑士click断环成树后就跟没上司一样是个树形dp,注意森林,longlong就行了,具体细节见这里P5022[NOIP2018提高组......
  • 基环树
    基环树1.定义基环树是一个由n个点及n条边组成的连通图,其比树多出一条边,所以称作基环树。2.分类基环树分为无向基环树和有向基环树。而有向基环树又分为内向基环树和外向基环树。内向基环树,即每个点出度为1的基环树;外向基环树,即每个点入度为1的基环树。3.解决方式对于有关......
  • 基环树
    基环树的定义为:一个有向或无向图中,只含有一个环的图,形式化的表达为:关于这种形状关键点主要在于找环,那么我们可以一步一步的去寻找,当这个点走着走着走到了某个环里,我们可以直接遍历整个环,然后打个标记,这样环就找到了具体的例题:E-ReachabilityinFunctionalGraph本题就是一......
  • 基环树找环
    abc167_dTeleporter#include<bits/stdc++.h>#defineptprintf(">>>")#definemid(((l)+(r))/2)usingnamespacestd;typedeflonglongll;typedeflongdoubleld;constllN=1e6+10,inf=1e18+10,mod=1e9+7;vector<ll>G[N];map&......
  • 置换 & 基环树题
    T1Statement给一个长度为\(n(\le10^5)\)的排列\(\{a_i\}\)。求一个排列\(\{b_i\}\),使得\(a_i=b_{b_i}\),或输出不存在。Solution先把所有排列变成置换对于任意排列\(\{p_i\}\),它转成置换后都是\(i\top_i\),故有\(i\top_i\top_{p_i}\top_{p_{p_i}}\to...\)所以所有......
  • 基环树算法总结
    基环树算法总结一、什么是基环树基环树,顾名思义,有两个要素:环和树。因此,基环树就是一棵树的一个节点,扩成一个环,做题时,多棵基环树组成的基环树森林,常以如下方式出现:每个点只有一个出边。每个点只有一个入边。图中一共有\(n\)个点,\(n\)条边。那么,基环树类型的题目应该怎......