# BZOJ 3197 assassin（树形DP+费用流）

code(第一次写费用流转移的DP，有参考大牛们的BLOG)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define N 705
#define seed 9875321
#define inf 1000000000
using namespace std;
{
char c=getchar(); int num=0,f=1;
while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }
while (c<='9'&&c>='0') { num=num*10+c-'0'; c=getchar(); }
return num*f;
}
struct edge{
int to,ne;
bool del;
}e[N<<1];
inline void push(int x,int y) { e[++tot].to=y; e[tot].ne=head[x]; head[x]=tot; }
unsigned long long H[N];
pair<int,pair<unsigned long long,int> > w[N];
pair<unsigned long long,int> p1[N],p2[N];
struct Network{
int S,T,tot,head[25],dis[25],pre[25]; bool vis[25];
struct edge{
int fr,to,ne,c,v;
}e[450];
void clear(int n) { S=0,T=n+1; tot=1; for (int i=S;i<=T;i++) head[i]=0; }
void push(int x,int y,int flow,int cost)
{
}
bool spfa()
{
for (int i=S;i<=T;i++) dis[i]=inf;
queue<int> q; dis[S]=0; vis[S]=true; q.push(S);
while (!q.empty())
{
int now=q.front(); q.pop();
{
int v=e[i].to;
if (e[i].v&&dis[now]+e[i].c<dis[v])
{
dis[v]=dis[now]+e[i].c;
pre[v]=i;
if (!vis[v]) vis[v]=true,q.push(v);
}
}
vis[now]=false;
}
return dis[T]!=inf;
}
int mcf()
{
for (int i=T;i!=S;i=e[pre[i]].fr) e[pre[i]].v--,e[pre[i]^1].v++;
return dis[T];
}
}flow;
void getrt(int now,int pre)
{
siz[now]=1; int tmp=0;
{
int v=e[i].to; if (v==pre) continue;
getrt(v,now); siz[now]+=siz[v];
tmp=max(tmp,siz[v]);
}
tmp=max(tmp,n-siz[now]);
if (tmp<mn) mn=tmp,h[0]=now,h[1]=0;
else if (tmp==mn) h[1]=now;
}
void geth(int now,int pre,int dep)
{
fa[now]=pre; deep[now]=dep;
{
int v=e[i].to; if (v==pre||e[i].del) continue;
geth(v,now,dep+1);
}
int top=0;
{
int v=e[i].to; if (v==pre||e[i].del) continue;
tmp[++top]=H[v];
}
sort(tmp+1,tmp+top+1);
H[now]=233;
for (int i=1;i<=top;i++) (((H[now]*=seed)^=tmp[i])+=tmp[i])^=tmp[i];
}
void solve(int x,int y)
{
int s1=0,s2=0;
{
int v=e[i].to; if (v==fa[x]||e[i].del) continue;
p1[++s1]=make_pair(H[v],v);
}
{
int v=e[i].to; if (v==fa[y]||e[i].del) continue;
p2[++s2]=make_pair(H[v],v);
}
sort(p1+1,p1+s1+1); sort(p2+1,p2+s2+1);
for (int i=1;i<=s1;i++)
{
int j=i;
while (j<s1&&p1[j+1].first==p1[j].first) j++;
int len=j-i+1;
flow.clear(len*2);
for (int k=i;k<=j;k++)
for (int l=i;l<=j;l++)
flow.push(k-i+1,l-i+1+len,1,f[p1[k].second][p2[l].second]);
for (int k=1;k<=len;k++)
flow.push(flow.S,k,1,0),flow.push(k+len,flow.T,1,0);
while (flow.spfa()) f[x][y]+=flow.mcf();
i=j;
}
if (a[x]!=b[y]) f[x][y]++;
}
int main()
{
for (int i=1;i<n;i++)
{
push(x,y); push(y,x);
}
for (int i=1;i<=n;i++) a[i]=read();
for (int i=1;i<=n;i++) b[i]=read();
getrt(1,0);
if (h[1])
{
if (e[i].to==h[1]) e[i].to=e[i^1].to=root=n+1;
push(n+1,h[0]); push(n+1,h[1]); n++;
}
else root=h[0];
geth(root,0,1);
for (int i=1;i<=n;i++) w[i]=make_pair(-deep[i],make_pair(H[i],i));
sort(w+1,w+n+1);
for (int i=1;i<=n;i++)
{
int j=i;
while (j<n&&w[j+1].first==w[j].first&&w[j+1].second.first==w[j].second.first) j++;
for (int k=i;k<=j;k++)
for (int l=i;l<=j;l++)
solve(w[k].second.second,w[l].second.second);
i=j;
}
printf("%d",f[root][root]);
return 0;
}