luogu P3296 [SDOI2013]刺客信条

题面传送门
首先肯定要找到任意一个在所有形态树中都一样的点,那么肯定找到重心。
然后找到中心以后设\(dp_{i,j}\)为\(i\)与\(j\)子树的最小答案。
然后对于这两个点的子树KM一下就可以得到答案了再加上自己。
时间复杂度\(O(11n^2)\)
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define lb long db
#define N 700
#define K 20
#define mod 998244353
#define Mod 998244352
#define eps (1e-4)
#define U unsigned int
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
using namespace std;
int n,m,k,x[N+5],y[N+5],root,dp[N+5][N+5],A[N+5],B[N+5],nx,ny,cnt,siz[N+5],F[N+5];vector<int> Son[N+5];
struct yyy{int to,z;};
struct ljb{int head,h[N+5];yyy f[N+5<<1];I void add(int x,int  y){f[++head]=(yyy){y,h[x]};h[x]=head;}}s,Cl;
struct Graph{
	int n,W[K+5][K+5],vx[K+5],vy[K+5],px[K+5],py[K+5],pre[K+5],slack[K+5],lx[K+5],ly[K+5],ToT;queue<int> Q;
	I void clear(){Me(W,-0x3f);Me(lx,-0x3f);Me(ly,0);Me(px,0);Me(py,0);Me(pre,0);}
	I void aug(int x){while(x) py[x]=pre[x],swap(x,px[pre[x]]);}
	I void insert(int x,int y,int z){n=z;for(int i=0;i<n;i++) for(int j=0;j<n;j++) W[i+1][j+1]=max(W[i+1][j+1],-dp[Son[x][i]][Son[y][j]]),lx[i+1]=max(lx[i+1],-dp[Son[x][i]][Son[y][j]]);}
	I void bfs(int x){
		Me(vx,0);Me(vy,0);Me(slack,0x3f);re int i;while(!Q.empty()) Q.pop();Q.push(x);while(1){
			while(!Q.empty()){
	    		x=Q.front();Q.pop();vx[x]=1;for(i=1;i<=n;i++){
		    		if(vy[i]||slack[i]<=lx[x]+ly[i]-W[x][i]) continue;pre[i]=x;slack[i]=lx[x]+ly[i]-W[x][i];if(!slack[i]){vy[i]=1;if(!py[i]) return aug(i);Q.push(py[i]);}
	    		}
	    	}ToT=1e9;for(i=1;i<=n;i++) !vy[i]&&(ToT=min(ToT,slack[i]));for(i=1;i<=n;i++) vx[i]&&(lx[i]-=ToT),vy[i]?(ly[i]+=ToT):(slack[i]-=ToT);for(i=1;i<=n;i++) if(!slack[i]&&!vy[i]){vy[i]=1;if(!py[i]) return aug(i);Q.push(py[i]);}
		}
	}
	I int KM(){re int i;for(i=1;i<=n;i++) bfs(i);for(ToT=0,i=1;i<=n;i++)ToT+=lx[i]+ly[i];return -ToT;}
}T;
I void Make(int x,int last){siz[x]=1;yyy tmp;for(int i=s.h[x];i;i=tmp.z)tmp=s.f[i],tmp.to^last&&(Make(tmp.to,x),siz[x]+=siz[tmp.to],F[x]=max(F[x],siz[tmp.to]));F[x]=max(F[x],n-siz[x]);}
I void dfs(int x,int last){yyy tmp;for(int i=s.h[x];i;i=tmp.z) tmp=s.f[i],tmp.to^last&&(dfs(tmp.to,x),Son[x].push_back(tmp.to),0);}
I void GetAns(int x,int y){
	if(Son[x].size()^Son[y].size()){dp[x][y]=1e3;return;}re int i,j;for(i=0;i<Son[x].size();i++){
		for(j=0;j<Son[y].size();j++)GetAns(Son[x][i],Son[y][j]);
	}T.clear();T.insert(x,y,Son[x].size());dp[x][y]=T.KM()+(A[x]^B[y]);
}
int main(){
//	freopen("1.in","r",stdin);
	re int i;scanf("%d",&n);for(i=1;i<n;i++) scanf("%d%d",&x[i],&y[i]),s.add(x[i],y[i]),s.add(y[i],x[i]);Make(1,0);for(i=1;i<=n;i++) F[i]<=n/2&&(cnt++,root=i);for(i=1;i<=n;i++) scanf("%d",&A[i]);for(i=1;i<=n;i++) scanf("%d",&B[i]);
	if(cnt==2){s=Cl;for(i=1;i<=n;i++) F[i]<=n/2&&((nx?ny:nx)=i);s.add(nx,n+1);nx>ny&&(swap(nx,ny),0);s.add(n+1,nx);s.add(n+1,ny);s.add(ny,n+1);for(i=1;i<=n;i++) (min(x[i],y[i])^nx||max(x[i],y[i])^ny)&&(s.add(x[i],y[i]),s.add(y[i],x[i]),0);n++;root=n;}
	dfs(root,0);GetAns(root,root);printf("%d\n",dp[root][root]);
}
上一篇:项目实战-点餐小程序-20 我的


下一篇:bof