联考day7_树和森林(lct.cpp)





上面是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
",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
"),void();
	int cc=0;
	for(rint i=1;i<=m;++i) if(!is_del[i]) ++cc;
	printf("%d
",cc);
	for(rint i=1;i<=m;++i) if(!is_del[i]) printf("%d ",i);
	printf("
");
}

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;
}
原文地址:https://www.cnblogs.com/Lour688/p/13910342.html