Description

故事发生在1486 年的意大利,Ezio 原本只是一个文艺复兴时期的贵族,后来因为家族成员受到圣殿骑士的杀害,决心成为一名刺客。最终,凭借着他的努力和出众的天赋,成为了杰出的刺客大师,他不仅是个身手敏捷的武林高手,飞檐走壁擅长各种暗杀术。刺客组织在他的带领下,为被剥削的平民声张正义,赶跑了原本统治意大利的圣殿骑士首领-教皇亚历山大六世。在他的一生中,经历了无数次惊心动魄、扣人心弦的探险和刺杀。

曾经有一次,为了寻找Altair 留下的线索和装备,Ezio 在佛罗伦萨中的刺客墓穴进行探索。这个刺客墓穴中有许多密室,且任何两个密室之间只存在一条唯一的路径。这些密室里都有一个刺客标记,他可以启动或者关闭该刺客标记。为了打开储存着线索和装备的储藏室,Ezio 必须操作刺客标记来揭开古老的封印。要想解开这个封印,他需要通过改变某些刺客标记的启动情况,使得所有刺客标记与封印密码“看起来一样”。

在这里,“看起来一样”的定义是:存在一种“标记”密室与“密码”密室之间一一对应的关系,使得密室间的连接情况和启动情况相同(提示中有更详细解释)。幸运的是,在Ezio 来到刺客墓穴之前,在Da Vinci 的帮助下,Ezio 已经得知了打开储藏室所需要的密码。

而你的任务则是帮助Ezio 找出达成目标所需要最少的改动标记次数。

Solution

首先固定一棵树,枚举另一棵树,显然另一棵树只有与固定的树同构才有可能产生贡献

如果固定的树以重心为根,那么另一棵树最多就只有重心为根才有可能同构了(可能有两个)

然后就是求改动次数最小值,设 \(f[x][y]\) 表示以第一棵树 \(x\) 为根的子树内和 第二棵树内 \(y\) 为根的子树内,达到目标最少需要改动的次数

我们发现只有同构的子树需要决策,我们把同构的子树分别拿出来,我们要做的就是做一个匹配,跑一边 \(KM\) 或者费用流就好了

\(f[x][y]\) 要记忆化一下,判断同构用树哈希即可

#include<bits/stdc++.h>
#define pb push_back
using namespace std;
template<class T>void gi(T &x){
int f;char c;
for(f=1,c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
for(x=0;c<='9'&&c>='0';c=getchar())x=x*10+(c&15);x*=f;
}
typedef unsigned long long ll;
const int N=1410,bas=10007;
int n,head[N],nxt[N*2],to[N*2],num=0,sz[N],F[N]={N},rt=0,a[N],b[N];ll v[N];
vector<int>v1[N],v2[N];
inline void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
inline void getroot(int x,int last){
sz[x]=1;F[x]=0;
for(int i=head[x],u;i;i=nxt[i]){
if((u=to[i])==last)continue;
getroot(u,x);sz[x]+=sz[u];
F[x]=max(F[x],sz[u]);
}
F[x]=max(F[x],n-sz[x]);
if(F[x]<F[rt])rt=x;
}
inline bool comp(const int &i,const int &j){return v[i]<v[j];}
inline void dfs(int x,int last,vector<int>*V){
sz[x]=1;v[x]=0;vector<int>().swap(V[x]);
for(int i=head[x],u;i;i=nxt[i]){
if((u=to[i])==last)continue;
dfs(u,x,V);sz[x]+=sz[u];
V[x].pb(u);
}
sort(V[x].begin(),V[x].end(),comp);
for(int i=V[x].size()-1;i>=0;i--)v[x]=v[x]*N+v[V[x][i]];
v[x]=v[x]*N+sz[x];
}
int f[N][N],c[N][N];
namespace sks{
int head[N],nxt[N*8],to[N*8],num=1,c[N*8],dis[N*8],S,T,ans=0;
queue<int>Q;int f[N],pre[N];bool vis[N];
inline void link(int x,int y,int z,int co){
nxt[++num]=head[x];to[num]=y;head[x]=num;dis[num]=z;c[num]=co;
nxt[++num]=head[y];to[num]=x;head[y]=num;dis[num]=0;c[num]=-co;
}
inline void init(){for(int i=S;i<=T;i++)head[i]=0;num=1;ans=0;}
inline bool spfa(){
for(int i=S;i<=T;i++)f[i]=N,vis[i]=0;
Q.push(S);vis[S]=1;f[S]=0;
while(!Q.empty()){
int x=Q.front();Q.pop();
for(int i=head[x],u;i;i=nxt[i]){
if(dis[i]<=0)continue;
u=to[i];
if(f[x]+c[i]<f[u]){
f[u]=f[x]+c[i];pre[u]=i;
if(!vis[u])Q.push(u),vis[u]=1;
}
}
vis[x]=0;
}
if(f[T]==N)return false;
int x=T;ans+=f[T];
while(x)dis[pre[x]]--,dis[pre[x]^1]++,x=to[pre[x]^1];
return true;
}
}
inline int solve(int n){
sks::init();
sks::S=0;sks::T=n+n+1;
for(int i=1;i<=n;i++){
sks::link(sks::S,i,1,0);sks::link(i+n,sks::T,1,0);
for(int j=1;j<=n;j++)sks::link(i,j+n,1,c[i][j]);
}
while(sks::spfa());
return sks::ans;
}
inline int sec(int x,int y){
if(f[x][y]!=-1)return f[x][y];
f[x][y]=b[y]^a[x];
for(int i=0,li=v1[x].size()-1;i<=li;i++){
int j=i;
while(j<li && v[v1[x][j+1]]==v[v1[x][i]])j++;
for(int k=i;k<=j;k++)
for(int l=i;l<=j;l++)sec(v1[x][k],v2[y][l]);
for(int k=i;k<=j;k++)
for(int l=i;l<=j;l++)c[k-i+1][l-i+1]=sec(v1[x][k],v2[y][l]);
f[x][y]+=solve(j-i+1);
i=j;
}
return f[x][y];
}
int main(){
freopen("pp.in","r",stdin);
freopen("pp.out","w",stdout);
cin>>n;
int x,y,ans=N;
for(int i=2;i<=n;i++){
gi(x);gi(y);
link(x,y);link(y,x);
}
for(int i=1;i<=n;i++)gi(a[i]);
for(int i=1;i<=n;i++)gi(b[i]);
getroot(1,1);dfs(rt,rt,v2);ll tmp=v[rt];
for(int i=1;i<=n;i++){
dfs(i,i,v1);
if(v[i]==tmp){
memset(f,-1,sizeof(f));
ans=min(ans,sec(i,rt));
}
}
cout<<ans<<endl;
return 0;
}

[SDOI2013]刺客信条的更多相关文章

  1. 【BZOJ3197】[SDOI2013]刺客信条

    [BZOJ3197][SDOI2013]刺客信条 题面 bzoj 洛谷 题解 关于树的同构,有一个非常好的性质: 把树的重心抠出来,那么会出现两种情况: 1.有一个重心,那么我们直接把这个重心作为树的 ...

  2. [BZOJ3197][SDOI2013]刺客信条assassin

    bzoj luogu Description 故事发生在1486 年的意大利,Ezio原本只是一个文艺复兴时期的贵族,后来因为家族成员受到圣殿骑士的杀害,决心成为一名刺客.最终,凭借着他的努力和出众的 ...

  3. BZOJ3197:[SDOI2013]刺客信条——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=3197 故事发生在1486 年的意大利,Ezio 原本只是一个文艺复兴时期的贵族,后来因为家族成员受 ...

  4. Bzoj3197/洛谷3296 [SDOI2013]刺客信条assassin(树的重心+树Hash+树形DP+KM)

    题面 Bzoj 洛谷 题解 (除了代码均摘自喻队的博客,可是他退役了) 首先固定一棵树,枚举另一棵树,显然另一棵树只有与这棵树同构才有可能产生贡献 如果固定的树以重心为根,那么另一棵树最多就只有重心为 ...

  5. JZOJ 3296 Luogu P3296 [SDOI2013]刺客信条

    前言 做法来自:@pzrpzr ,写一下!Orz pzr! 题目大意 \(n\) 个点的无根树,每个点有两个 \(0/1\) 权值,合适地安排节点在同构树中的顺序,使得前后对应的权值不同节点个数最小, ...

  6. [JZOJ3296] 【SDOI2013】刺客信条

    题目 题目大意 给你一棵树,树上每个节点有000或111的状态. 用最少的操作次数使得当前状态与目标状态同构. 思考历程 首先想到的是找重心. 因为根是不确定的,但重心只会有一个或两个,以重心为根就能 ...

  7. 【JZOJ3296】【SDOI2013】刺客信条(assassin)

    ╰( ̄▽ ̄)╭ Description 故事发生在1486 年的意大利,Ezio 原本只是一个文艺复兴时期的贵族,后来因为家族成员受到圣殿骑士的杀害,决心成为一名刺客.最终,凭借着他的努力和出众的天赋 ...

  8. BZOJ3130: [Sdoi2013]费用流[最大流 实数二分]

    3130: [Sdoi2013]费用流 Time Limit: 10 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 960  Solved: 5 ...

  9. Unity实现刺客信条灯光的思路探究

    灯光需求 类似刺客信条的开场CG动画,场景中打着酷炫的灯光,玩家在场景中行走可以感受到灯光很真实. 参考视频:http://www.iqiyi.com/w_19rqytbmvt.html 运行环境 安 ...

随机推荐

  1. LoadRunner监控Linux条件和解决方法

    注:内容来自网络 需要下载3个包: (1)rsh-0.17-14.i386.rpm (2)rsh-server-0.17-14.i386.rpm (3)rpc.rstatd-4.0.1.tar.gz ...

  2. 开启和查看mysql的bin-log日志

    [root@VM_0_7_centos data]# vim /etc/my.cnf [root@VM_0_7_centos data]# vim /etc/my.cnf [root@VM_0_7_c ...

  3. Java面向对象之构造代码块 入门实例

    一.基础概念 1.构造代码块,给所有对象进行初始化. 2.构造函数,只给对应的对象初始化. 3.局部代码块,控制局部变量的生命周期. 二.实例代码 class Person { private int ...

  4. 性能检测参考SQL语句

    /****** Object: StoredProcedure [dbo].[SP_CPU] Script Date: 12/09/2018 19:01:24 ******/ SET ANSI_NUL ...

  5. WPF优化:Freezable冻结对象

    原文:WPF优化:Freezable冻结对象 WPF虽然很美观,效果很炫,但是对资源的消耗也很大,尤其是初次接触WPF的人,因为很多地方虽然实现了想要的效果,但是由于经验问题,所以也会造成很大的资源浪 ...

  6. Idea 软件Project项目的jar依赖关系设置方法

    1.查看所依赖的jar文件 (1)File--->Project Structure (2)Modules--->project01---->dependencies,可见所缺少的j ...

  7. ES6问题记录--Promise

    在读[阮一峰]的 ES6 入门文档的时候,有一段代码是这样的. 文章中,还有一段是这样写的 所以,Promise.resolve(3).finally(()=>{}),解析出来的resolve ...

  8. 洛谷 P3380 【模板】二逼平衡树(树套树)

    题面 luogu 题解 2019年AC的第一道题~~ 函数名命名为rank竟然会ce 我写的是树状数组套值域线段树(动态开点) 操作1:询问\(k\)在\([l-r]\)这段区间有多少数比它小,再加\ ...

  9. Luogu P1273 有线电视网 树形DP

    又重构了一下...当然当初的题一看就看懂了QAQ 设f[i][j]表示以i为根的子树,有j个客户的最大收益 方程:f[u][j+k]=max(f[u][j+k],f[u][j]+f[v][k]-w(u ...

  10. Python-is, ==, cmp()

    is 主要是判断 2 个变量是否引用的是同一个对象,如果是的话,则返回 true,否则返回 false. 判断数字相等不要用 is 操作符 1 2 3 4 5 6 7 8 9 10 11 12 > ...