【SDOI2013】【BZOJ3197】assassin

Description

这里写图片描述

Input
这里写图片描述

Output

这里写图片描述

Sample Input

4

1 2

2 3

3 4

0 0 1 1

1 0 0 0
Sample Output

1
HINT

这里写图片描述

暑假时候高大哥出来考试的题
丢题解跑
gty大哥的题解

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define MAXN 710
#define GET (ch>='0'&&ch<='9')
#define ULL unsigned long long
#define base 43
using namespace std;
int n,top,root;
int S=0,T=29;
int a[MAXN],b[MAXN];
int fa[MAXN],size[MAXN],deep[MAXN],g[2];
int f[MAXN][MAXN];
ULL hash[MAXN];
struct edge
{
    int to;
    edge *next,*rev;
}e[MAXN<<1],*prev[MAXN];
struct node
{
    int deep,id;
    ULL hash;
    bool operator <(const node& a)const {   return deep==a.deep?hash<a.hash:deep>a.deep;    }
    bool operator ==(const node& a)const    {   return deep==a.deep&&hash==a.hash;  }
}s[MAXN];
void insert(int u,int v)    {   e[++top].to=v;e[top].next=prev[u];prev[u]=&e[top];  }
void in(int &x)
{
    char ch=getchar();x=0;
    while (!GET)    ch=getchar();
    while (GET) x=x*10+ch-'0',ch=getchar();
}
void dfs1(int x,int f)//Find G 
{
    size[x]=1;fa[x]=f;bool flag=1;
    for (edge *i=prev[x];i;i=i->next)
        if (i->to!=f)
        {
            dfs1(i->to,x);size[x]+=size[i->to];
            if (size[i->to]>n>>1)   flag=0;
        }
    if (n-size[x]>n>>1) flag=0;
    if (flag)   
        for (int i=0;i<=1;i++)  if (!g[i])  {   g[i]=x;break;   }
}
void dfs2(int x,int f)//Get Hash 
{
    deep[x]=deep[f]+1;int Top=0;ULL sta[MAXN];fa[x]=f;
    for (edge *i=prev[x];i;i=i->next)   if (i->to!=f)   dfs2(i->to,x);
    for (edge *i=prev[x];i;i=i->next)   if (i->to!=f)   sta[++Top]=hash[i->to];
    sort(sta+1,sta+Top+1);hash[x]=41;
    for (int i=1;i<=Top;i++)    (((hash[x]*=base)^=sta[i])+=sta[i])^=sta[i];
}
int tp,ret;
struct Edge
{
    int from,to,c,w;
    Edge *next,*rev;
}E[10010],*Prev[32],*from[32];
void Insert(int u,int v,int f,int w)    {   E[++tp].to=v;E[tp].from=u;E[tp].next=Prev[u];Prev[u]=&E[tp];E[tp].c=f;E[tp].w=w;    }
void add(int u,int v,int f,int w)   {   Insert(u,v,f,w);Insert(v,u,0,-w);E[tp].rev=&E[tp-1];E[tp-1].rev=&E[tp]; }
bool cmp(int a,int b)   {   return hash[a]<hash[b]; }
int spfa()
{
    bool vis[32];memset(vis,0,sizeof(vis));
    int dis[32];memset(dis,0x3f,sizeof(dis));
    vis[S]=1;dis[S]=0;queue<int>    q;q.push(S);
    while (!q.empty())
    {
        int x=q.front();q.pop();vis[x]=0;
        for (Edge *i=Prev[x];i;i=i->next)
            if (i->c>0&&dis[i->to]>dis[x]+i->w)
            {
                dis[i->to]=dis[x]+i->w;from[i->to]=i;
                if (!vis[i->to]) vis[i->to]=1,q.push(i->to);
            }
    }
    return dis[T]!=0x3f3f3f3f;
}
void dfs()
{
    int minn=0x3f3f3f3f;
    for (Edge *i=from[T];i;i=from[i->from]) minn=min(minn,i->c);
    for (Edge *i=from[T];i;i=from[i->from]) ret+=minn*i->w,i->c-=minn,i->rev->c+=minn;
}
int calc(int x,int y)
{
    int sta1[MAXN],sta2[MAXN],tp1=0,tp2=0,i=0,j=0;
    for (edge *i=prev[x];i;i=i->next)   if (i->to!=fa[x])   sta1[++tp1]=i->to;
    for (edge *i=prev[y];i;i=i->next)   if (i->to!=fa[y])   sta2[++tp2]=i->to;
    sort(sta1+1,sta1+tp1+1,cmp);sort(sta2+1,sta2+tp2+1,cmp);
    memset(Prev,0,sizeof(Prev));memset(E,0,sizeof(Edge)*(tp+3));tp=0;ret=0;
    for (i=1;i<=tp1;i=j)
    {
        for (j=i+1;j<=tp1&&hash[sta1[i]]==hash[sta1[j]];j++);
        for (int k=i;k<j;k++)   for (int l=i;l<j;l++)   add(k,tp1+l,1,f[sta1[k]][sta2[l]]);
    }
    for (int i=1;i<=tp1;i++)    add(S,i,1,0),add(i+tp1,T,1,0);
    while (spfa())  dfs();
    return ret+(a[x]^b[y]);
}
int main()
{
    in(n);int u,v,r=0;
    for (int i=1;i<n;i++)   in(u),in(v),insert(u,v),insert(v,u),e[top].rev=&e[top-1],e[top-1].rev=&e[top];
    for (int i=1;i<=n;i++)  in(a[i]);
    for (int i=1;i<=n;i++)  in(b[i]);
    dfs1(1,0);
    if (g[1])
    {
        root=++n;
        for (edge *i=prev[g[0]];i;i=i->next)    if (i->to==g[1])    {   i->to=i->rev->to=n;break;   }
        insert(n,g[0]);insert(n,g[1]);
    }
    else    root=g[0];
    dfs2(root,0);
    for (int i=1;i<=n;i++)  s[i]=(node){deep[i],i,hash[i]};
    sort(s+1,s+n+1);
    for (int l=1;l<=n;l=r)
    {
        for (r=l+1;r<=n&&s[l]==s[r];r++);
        for (int x=l;x<r;x++)   for (int y=l;y<r;y++)
            f[s[x].id][s[y].id]=calc(s[x].id,s[y].id);
    }
    cout<<f[root][root];
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值