ICode9

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

联赛模拟测试27_树和森林(lct.cpp)

2020-11-01 17:32:02  阅读:184  来源: 互联网

标签:rt lct 27 int siz maxn cpp dp dis






上面是pdf题解,下面自己说一下

子任务一:

对于两棵树的比较好求,对于每个联通块,求出每个点到其他点的距离之和

一棵树内部的贡献就是所有的点的\(dis_{sum}\)相加,然后除以2。

树与树之间的贡献:对于上面的每个联通块中的每个点求出的\(dis_{sum}\),取最大值设为,\(max_{dis}[1],max_{dis}[2]\).

然后就是\(max_{dis}[1]*siz[rt[2]]+max_{dis}[2]*siz[rt[1]]+siz[rt[1]]*siz[rt[2]]\)

对于三棵树的,需要考虑哪棵树在中间,假设三棵树编号1,2,3。2在中间,\(1\)和\(2\)通过\(x,y\)相连,2和3通过

\(u,v\)相连,那么树内部的贡献和上面一样.除此之外,

树1和\((x,y)\)这条边贡献 \((dis_{sum}[1,x]+siz[rt[1]])*(n-siz[rt[1]])\)

树3和\((u,v)\)这条边贡献 \((dis_{sum}[3,v]+siz[rt[3]])*(n-siz[rt[3]])\)

树2和\((y,u)\)这条边贡献 \(dis_{sum}[2,y]*siz[rt[1]]+dis[2,u]*siz[rt[3]]+d(y,u)*siz[rt[1]]*siz[rt[3]]\)

发现前两行可以通过两棵树的方法,取max得到答案,最后一行要再用个换根dp,\(dp_{down}[y]\)和\(dp_{up}[y]\)记录,对于固定的y,

它下面和上面的最优的 \(dis[2,u]*siz[rt[3]]+d(y,u)*siz[rt[1]]*siz[rt[3]]\),两遍\(dfs\),\(O(n)\)求出。最后求答案时候再加上一个\(dis_{sum}[2,y]*siz[rt[1]]\)

子任务二:

有一种很简单的方法,我们考虑从叶子节点着手,因为叶子节点限制比较少,要删只能删父边,删完后又会出现新的叶子

叶子是白色肯定得删父边,黑色就不删,这样\(dfs\),不断向上传递,最后如果根节点要删父边肯定不合法,否则合法

而且只有这一种方案,直接输出即可

Code
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#define rint register int
using namespace std;

const int maxn=1e5+5;
int n,m,blo_cnt;
int rt[4];
int siz[maxn],fa[maxn];
long long dis_sum[maxn];
long long max_dis[4];
long long in_dis[4];
char col[maxn];
bool vis[maxn],is_del[maxn],du[maxn];
vector < int > vec[maxn];
vector < int > vec_id[maxn];
vector < long long > pre[maxn];
vector < long long > suf[maxn];

void dfs1(int x,int prt,int dep){
	vis[x]=1,siz[x]=1,fa[x]=prt;
	for(rint i=0;i<(int)vec[x].size();++i){
		const rint y=vec[x][i];
		if(vis[y]) continue;
		dfs1(y,x,dep+1);
		siz[x]+=siz[y];
	}
	dis_sum[rt[blo_cnt]]+=dep;
}

void dfs2(int x,int id){
	for(rint i=0;i<(int)vec[x].size();++i){
		const rint y=vec[x][i];
		if(y==fa[x]) continue;
		dis_sum[y]=dis_sum[x]+siz[rt[id]]-2ll*siz[y];
		dfs2(y,id);
	}
	max_dis[id]=max(max_dis[id],dis_sum[x]);
	in_dis[id]+=dis_sum[x];
}

long long dp_down[maxn],dp_up[maxn],dp[maxn];
// siz1 * dis2,y +     siz3 * dis2,u + d(y,u) * siz1 * siz3
// dp_down or up is to calc [ siz3 * dis2,u + d(y,u) * siz1 * siz3 ]

void dfs_down(int x,int A,int B){
	dp_down[x]=dis_sum[x]*B;
	long long res=0;
	for(rint i=0;i<(int)vec[x].size();++i){
		pre[x].push_back(res);
		const rint y=vec[x][i];
		if(y==fa[x]) continue;
		dfs_down(y,A,B);
		res=max(res,dp_down[y]+1ll*A*B);
	}
	dp_down[x]=max(dp_down[x],res);
	res=0;
	for(rint i=(int)vec[x].size()-1;i>=0;--i){
		suf[x].push_back(res);
		const rint y=vec[x][i];
		if(y==fa[x]) continue;
		res=max(res,dp_down[y]+1ll*A*B);
	}
}

void dfs_up(int x,int A,int B,int id_pre,int id_suf){
	dp_up[x]=dis_sum[x]*B;
	if(fa[x]) dp_up[x]=max(dp_up[x],max(dp_up[fa[x]],max(pre[fa[x]][id_pre],suf[fa[x]][id_suf]))+1ll*A*B);
	dp[x]=max(dp_down[x],dp_up[x])+dis_sum[x]*A;
	
	for(rint i=0;i<(int)vec[x].size();++i){
		const rint y=vec[x][i];
		if(y==fa[x]) continue;
		dfs_up(y,A,B,i,(int)vec[x].size()-i-1);
		dp[x]=max(dp[x],dp[y]);
	}
}

void solve1(){
	long long ans=0;
	if(blo_cnt==2) ans=max_dis[1]*siz[rt[2]]+max_dis[2]*siz[rt[1]]+1ll*siz[rt[1]]*siz[rt[2]];
	else{
		long long Const1=(max_dis[1]+siz[rt[1]])*(n-siz[rt[1]]);
		long long Const2=(max_dis[2]+siz[rt[2]])*(n-siz[rt[2]]);
		long long Const3=(max_dis[3]+siz[rt[3]])*(n-siz[rt[3]]);
		
		dfs_down(rt[2],siz[rt[1]],siz[rt[3]]);
		dfs_up(rt[2],siz[rt[1]],siz[rt[3]],0,0);
		ans=max(ans,Const1+Const3+dp[rt[2]]);
		
		dfs_down(rt[3],siz[rt[1]],siz[rt[2]]);
		dfs_up(rt[3],siz[rt[1]],siz[rt[2]],0,0);
		ans=max(ans,Const1+Const2+dp[rt[3]]);
		
		dfs_down(rt[1],siz[rt[2]],siz[rt[3]]);
		dfs_up(rt[1],siz[rt[2]],siz[rt[3]],0,0);
		ans=max(ans,Const2+Const3+dp[rt[1]]);
	}
	for(rint i=1;i<=blo_cnt;++i) ans+=in_dis[i];
	printf("%lld\n",ans);
}

// delete white leaves
// this is to judge if the edge to the father need to be cut

bool dfs_del_leaf(int x,int in_edge){
	bool del_cc=0;
	for(rint i=0;i<(int)vec[x].size();++i){
		const rint y=vec[x][i];
		if(y==fa[x]) continue;
		del_cc^=dfs_del_leaf(y,vec_id[x][i]);
	}
	if(col[x]=='B'){
		if(du[x]==del_cc) return is_del[in_edge]=1;
		return 0;
	}
	else{
		if(du[x]!=del_cc) return is_del[in_edge]=1;
		return 0;
	}
}

void solve2(){
	for(int i=1;i<=blo_cnt;++i) if(dfs_del_leaf(rt[i],0)) return printf("-1\n"),void();
	int cc=0;
	for(rint i=1;i<=m;++i) if(!is_del[i]) ++cc;
	printf("%d\n",cc);
	for(rint i=1;i<=m;++i) if(!is_del[i]) printf("%d ",i);
	printf("\n");
}

int main(){
	freopen("lct.in","r",stdin);
	freopen("lct.out","w",stdout);
	scanf("%d%d%s",&n,&m,col+1);
	for(int i=1,x,y;i<=m;++i){
		scanf("%d%d",&x,&y);
		vec[x].push_back(y),vec_id[x].push_back(i);
		vec[y].push_back(x),vec_id[y].push_back(i);
		du[x]^=1,du[y]^=1;
	}
	for(rint i=1;i<=n;++i){
		if(!vis[i]){
			rt[++blo_cnt]=i;
			dfs1(i,0,0);
		}
	}
	for(int i=1;i<=blo_cnt;++i){
		dfs2(rt[i],i);
		in_dis[i]/=2;
	}
	solve1(),solve2();
	return 0;
}

标签:rt,lct,27,int,siz,maxn,cpp,dp,dis
来源: https://www.cnblogs.com/Lour688/p/13910342.html

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

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

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

ICode9版权所有