标签:重点 lan and splay int dfs line spl class
自己树形dp太菜了,要重点搞
终于自己做了一道不算那么毒瘤的换根dp
令 \(f[u]\) 表示以 \(u\) 为根,子树内总共需要交换的边数, \(up[u]\) 表示以 \(u\) 为根,子树外总共需要交换的边数。
Dfs1 求出 \(f[u]\) ,就有:
\[f[u]=\sum_{v∈son[u]} f[v] + (edge[u->v] == 1)\]
edge[u->v] 表示 u->v 这条边的方向是不是 u->v
Dfs2 求出 \(up[v]\)(注意,是从u点求u的儿子点v),容斥一下,就有:
\[up[v]=f[u]-f[v]+up[u]+(+1 / -1)\]
(+1 / -1) 是看 edge[u->v]是否等于 1,是的话就有多一条边交换方向,不是的话就要-1,因为多算了一条边
Code
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
inline int read() {
int x=0,f=1; char ch=getchar();
while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
return x * f;
}
const int N = 2e5+7;
int n,cnt;
int head[N],f[N],up[N];
struct Edge {
int next,to,flag;
}edge[N<<1];
inline void add(int u,int v,int flag) {
edge[++cnt] = (Edge)<%head[u],v,flag%>;
head[u] = cnt;
}
void Dfs1(int u,int fa) {
for(int i=head[u];i;i=edge[i].next) {
int v = edge[i].to;
if(v != fa) {
Dfs1(v,u);
f[u] += f[v] + (edge[i].flag==0); //·′±?
}
}
}
void Dfs2(int u,int fa) {
for(int i=head[u];i;i=edge[i].next) {
int v = edge[i].to;
if(v != fa) {
up[v] = f[u] - f[v] + up[u];
if(edge[i].flag == 1) up[v]++;
else up[v]--;
Dfs2(v,u);
}
}
}
int main()
{
n = read();
for(int i=1,u,v;i<=n-1;++i) {
u = read(), v = read();
add(u,v,1), add(v,u,0);
}
Dfs1(1,0);
Dfs2(1,0);
int ans = INF;
for(int i=1;i<=n;++i)
ans = min(ans,f[i]+up[i]);
printf("%d\n",ans);
for(int i=1;i<=n;++i)
if(f[i]+up[i] == ans) printf("%d ",i);
return 0;
}
/*
4
1 4
2 4
3 4
2
1 2 3
*/
标签:重点 lan and splay int dfs line spl class
原文地址:https://www.cnblogs.com/BaseAI/p/11824204.html