1. 程式人生 > >SEERC 2017 L Divide and Conquer

SEERC 2017 L Divide and Conquer

題面

在這裡插入圖片描述

題意

給出由A,B兩棵樹重合後組成的一張圖,問至少刪掉幾條邊才能將圖分成兩塊。

做法

首先,這張圖一共有 n n 個點, 2 ( n

1 ) 2*(n-1) 條邊,因此度數最小的點的度數一定小於等於3,這就說明了答案一定為2或3,這也就說明了A,B兩棵樹中一定有一棵樹種只刪了一條邊,因此我們可以暴力列舉在A樹中刪掉的是哪條邊,然後統計B樹中有幾條邊連線著A樹刪掉這條邊後的兩個聯通塊,而這個可以用樹上差分來解決:
對於B樹中的每一條邊 u
v u-v
,令 n u m [ u ]
+ + , n u m [ v ] , n u m [ l c a ( u , v ) ] = 2 ( A l c a ) num[u]++,num[v]--,num[lca(u,v)]-=2(A樹上的lca)
.
這樣A中每個點的子樹 n u m num 和即為刪去這個點和它父親的連邊之後兩個聯通塊間B的邊數。
因為如果 u u , v v 在同一聯通塊中,則它們的 l c a lca 也一定在同一聯通塊,不會對答案做出貢獻,反之必然會對答案做出1的貢獻。

程式碼

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#define P pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define N 100100
using namespace std;

int n,ans[5],num[N],in[N],out[N],fa[N],tt;
bool vis[N];
P ba[N],bb[N];
struct Sz
{
	int sz[N];
	inline int lb(int u){return u&(-u);}
	inline void add(int u,int v){for(;u<=n;u+=lb(u)) sz[u]+=v;}
	inline int as(int u){int res=0;for(;u;u-=lb(u)) res+=sz[u];return res;}
	inline void clear(){memset(sz,0,sizeof(sz));}
	inline int ask(int u){return as(out[u])-as(in[u]-1)+1;}
};
Sz sz;
vector<int>son[N],que[N];

int ff(int u){return u==fa[u]?u:fa[u]=ff(fa[u]);}

void dfs(int now,int last)
{
	in[now]=++tt;
	int i,t;
	for(i=0;i<son[now].size();i++)
	{
		t=son[now][i];
		if(t==last) continue;
		dfs(t,now);
	}
	for(i=0;i<que[now].size();i++) if(vis[que[now][i]]) num[ff(que[now][i])]-=2;
	if(last!=-1) fa[ff(now)]=ff(last);
	out[now]=tt;
	vis[now]=1;
}

int main()
{
	int i,j,t;
	cin>>n;
	for(i=1;i<n;i++)
	{
		scanf("%d%d",&ba[i].fi,&ba[i].se);
		son[ba[i].fi].push_back(ba[i].se);
		son[ba[i].se].push_back(ba[i].fi);
	}
	for(i=1;i<n;i++)
	{
		scanf("%d%d",&bb[i].fi,&bb[i].se);
		que[bb[i].fi].push_back(bb[i].se);
		que[bb[i].se].push_back(bb[i].fi);
		num[bb[i].fi]++,num[bb[i].se]++;
	}
	for(i=1;i<=n;i++) fa[i]=i;
	dfs(1,-1);
	for(i=1;i<=n;i++) sz.add(in[i],num[i]);
	for(i=2;i<=n;i++)
	{
		t=sz.ask(i);
		if(t<=3) ans[t]++;
	}
	if(ans[2])
	{
		cout<<2<<" "<<ans[2];
		return 0;
	}
	memset(num,0,sizeof(num));
	memset(vis,0,sizeof(vis));
	for(i=1;i<=n;i++)
	{
		fa[i]=i;
		son[i].clear();
		que[i].clear();
		sz.clear();
	}
	tt=0;
	for(i=1;i<n;i++)
	{
		son[bb[i].fi].push_back(bb[i].se);
		son[bb[i].se].push_back(bb[i].fi);
	}
	for(i=1;i<n;i++)
	{
		que[ba[i].fi].push_back(ba[i].se);
		que[ba[i].se].push_back(ba[i].fi);
		num[ba[i].fi]++,num[ba[i].se]++;
	}
	dfs(1,-1);
	for(i=1;i<=n;i++) sz.add(in[i],num[i]);
	for(i=2;i<=n;i++)
	{
		t=sz.ask(i);
		if(t<=3) ans[t]++;
	}
	cout<<3<<' '<<ans[3];
	return 0;
}