传送门:
思路:设f[i][cnt][col]表示i的子树中,黑节点为cnt,i的颜色为col时,最小的端点颜色不同的边的数量。
转移就是 f[x][cnt][col]=min(f[son[x]][i][col_son]+f[x][cnt-i][col]+(col!=col_son));
看起来这是O(n^3)的,实际上这是O(n^2)的
对于一个点x,对x操作的复杂度就是
观察一下就会发现,每对叶子节点(x,y)只会在lca(x,y)处对复杂度有一次贡献
于是复杂度就是O(n^2)的了。
#include#include #include const int maxn=5010,maxm=10010;using namespace std;int n,m,pre[maxm],now[maxn],son[maxm],val[maxm],f[maxn][maxn][2],g[maxn][2],siz[maxn],tot,in[maxn];bool isl[maxn];void add(int a,int b){pre[++tot]=now[a],now[a]=tot,son[tot]=b,in[b]++;}//0 white 1 blackvoid dfs(int x,int fa){ if (isl[x]){siz[x]=1,f[x][0][0]=f[x][1][1]=0;return;} f[x][0][0]=f[x][0][1]=0; for (int y=now[x];y;y=pre[y])if (son[y]!=fa){ dfs(son[y],x); //printf("fuckpp%d %d\n",son[y],siz[x]); memset(g,63,sizeof(g)); for (int i=siz[x];i>=0;i--) for (int j=siz[son[y]];j>=0;j--){ //if (son[y]==8&&x==5) printf("%d %d\n",i,j); g[i+j][0]=min(g[i+j][0],f[x][i][0]+f[son[y]][j][0]); g[i+j][1]=min(g[i+j][1],f[x][i][1]+f[son[y]][j][1]); g[i+j][0]=min(g[i+j][0],f[x][i][0]+f[son[y]][j][1]+1); g[i+j][1]=min(g[i+j][1],f[x][i][1]+f[son[y]][j][0]+1); } memcpy(f[x],g,sizeof(f[x])); siz[x]+=siz[son[y]]; }}int main(){ scanf("%d",&n); for (int i=1,a,b;i >1][0],f[i][siz[i]>>1][1])); break; }// for (int i=1;i<=n;i++) printf("%d %d\n",i,siz[i]); return 0;}