CF708C 【Centroids】树上DP
洛谷同步博客
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;
}
如有不当,请指出。