SEERC 2017 L Divide and Conquer
阿新 • • 發佈:2018-11-02
題面
題意
給出由A,B兩棵樹重合後組成的一張圖,問至少刪掉幾條邊才能將圖分成兩塊。
做法
首先,這張圖一共有
個點,
條邊,因此度數最小的點的度數一定小於等於3,這就說明了答案一定為2或3,這也就說明了A,B兩棵樹中一定有一棵樹種只刪了一條邊,因此我們可以暴力列舉在A樹中刪掉的是哪條邊,然後統計B樹中有幾條邊連線著A樹刪掉這條邊後的兩個聯通塊,而這個可以用樹上差分來解決:
對於B樹中的每一條邊
,令
.
這樣A中每個點的子樹
和即為刪去這個點和它父親的連邊之後兩個聯通塊間B的邊數。
因為如果
,
在同一聯通塊中,則它們的
也一定在同一聯通塊,不會對答案做出貢獻,反之必然會對答案做出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;
}