zoukankan      html  css  js  c++  java
  • 联考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;
    }
    
  • 相关阅读:
    搭建typescript练习环境
    原有vue项目支持typescript
    express使用session
    express使用cookie
    javascript原型链
    javascript事件循环
    express中间件及body-parser第三方中间件获取post传值
    express路由、静态托管、ejs模板引擎
    nodejs驱动mongodb 实现数据增删改查,将数据库数据渲染在页面,通过表单项数据库新增数据
    柏松分布
  • 原文地址:https://www.cnblogs.com/Lour688/p/13910342.html
Copyright © 2011-2022 走看看