CF708C 【Centroids】樹上DP
阿新 • • 發佈:2019-01-12
洛谷同步部落格
1.我們先來簡化一下問題
如果題目不讓我們改造這棵樹,就很好求了。
先求出
(如下圖),
為無根樹中的任意一條有向邊(我們在鄰接表中使用一對有向邊
和
來表示,其中
為
的反向邊,表示以
(表示邊e的尾)為根的子樹的大小。可知
。
要求出
和
,可以用一個
來解決(
可以用一個小技巧:e^1)
上程式碼:
void dfs(int u,int e)
{
size[e]=1;
for(int i=0;i<(int)G[u].size();i++)
if(G[u][i]!=(e^1))
{
int v=edges[G[u][i]].v;
dfs1(v,G[u][i]);
add(u,G[u][i]);
size[e]+=size[G[u][i]];
}
size[e^1]=n-size[e];
}
這樣,就可以了:把每個節點的各個子節點的 值掃描一遍,有 就說明 不是樹的中心。
2.說了半天,回到原問題(還有啊! !)
做好迎接挑戰的準備吧!
我們要把一條邊刪去,並連上另一條新邊,也就是說,要把一個子樹切割下來,在把他連到新的節點上。
我們可以計算一個
(
的定義同
),表示以
為根的子樹中最多可以割下多少個節點,可知
。
可以在原來的
的基礎上再加一個
(並用一個數據結構來輔助實現):
void add(int u,int i)
{
if(best[u]<=c[i])
{
sec[u]=best[u];
best[u]=c[i];
idx[u]=i;
}
else sec[u]=max(sec[u],c[i]);
}
int query(int u,int i)
{
if(i!=idx[u]) return best[u];
else return sec[u];
}
void dfs1(int u,int e)
{
size[e]=1;
c[e]=0;
for(int i=0;i<(int)G[u].size();i++)
if(G[u][i]!=(e^1))
{
int v=edges[G[u][i]].v;
dfs1(v,G[u][i]);
add(u,G[u][i]);
size[e]+=size[G[u][i]];
c[e]=max(c[e],c[G[u][i]]);
}
size[e^1]=n-size[e];
if(size[e]<=n/2) c[e]=size[e];
}
void dfs2(int u,int e)
{
add(u,e^1);
for(int i=0;i<(int)G[u].size();i++)
if(G[u][i]!=(e^1))
{
if(size[G[u][i]^1]<=n/2) c[G[u][i]^1]=size[G[u][i]^1];
else c[G[u][i]^1]=query(u,G[u][i]);
dfs2(edges[G[u][i]].v,G[u][i]);
}
}
3.於是我們就大功告成了
獻上我醜陋的程式碼:
#include<iostream>
#include<vector>
using namespace std;
const int maxn=800005;
struct Edge
{
int u,v;
Edge(int x,int y): u(x),v(y){}
};
int n,size[maxn],c[maxn],best[maxn],sec[maxn],idx[maxn];
vector<Edge> edges;
vector<int> G[maxn];
void add(int u,int i)
{
if(best[u]<=c[i])
{
sec[u]=best[u];
best[u]=c[i];
idx[u]=i;
}
else sec[u]=max(sec[u],c[i]);
}
int query(int u,int i)
{
if(i!=idx[u]) return best[u];
else return sec[u];
}
void dfs1(int u,int e)
{
size[e]=1;
c[e]=0;
for(int i=0;i<(int)G[u].size();i++)
if(G[u][i]!=(e^1))
{
int v=edges[G[u][i]].v;
dfs1(v,G[u][i]);
add(u,G[u][i]);
size[e]+=size[G[u][i]];
c[e]=max(c[e],c[G[u][i]]);
}
size[e^1]=n-size[e];
if(size[e]<=n/2) c[e]=size[e];
}
void dfs2(int u,int e)
{
add(u,e^1);
for(int i=0;i<(int)G[u].size();i++)
if(G[u][i]!=(e^1))
{
if(size[G[u][i]^1]<=n/2) c[G[u][i]^1]=size[G[u][i]^1];
else c[G[u][i]^1]=query(u,G[u][i]);
dfs2(edges[G[u][i]].v,G[u][i]);
}
}
int main()
{
cin>>n;
for(int i=1;i<n;i++)
{
int u,v;
cin>>u>>v;
edges.push_back(Edge(u,v));
edges.push_back(Edge(v,u));
G[u].push_back(edges.size()-2);
G[v].push_back(edges.size()-1);
}
dfs1(1,edges.size());
dfs2(1,edges.size());
for(int i=1;i<=n;i++)
{
bool ok=true;
for(int j=0;j<(int)G[i].size();j++)
if(size[G[i][j]]-c[G[i][j]]>n/2)
{
ok=false;
break;
}
cout<<ok<<' ';
}
return 0;
}
如有不當,請指出。