【CF613D】Kingdom and its Cities 虚树+树形DP

【CF613D】Kingdom and its Cities

题意:给你一棵树,每次询问给出k个关键点,问做多干掉多少个非关键点才能使得所有关键点两两不连通。

$n,\sum k\le 10^5$

题解:刷虚树板子啦!

首先如果两个关键点相邻则无解。然后建出虚树,进行树形DP。设f[i]表示i子树中的关键点都不连通,且i子树中的点与外面的点也不连通的最小花费,g[i]表示i子树重的关键点都不连通,且子树中只有一个点与外面的点连通的最小花费。转移时讨论一波即可。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn=100010;
int n,m,now,cnt,top;
int to[maxn<<1],nxt[maxn<<1],head[maxn],fa[19][maxn],Log[maxn],dep[maxn],A[maxn],vis[maxn],st[maxn],f[maxn],g[maxn],p[maxn],q[maxn];
vector<int> ch[maxn];
void dfs(int x)
{
	p[x]=++q[0],q[q[0]]=x;
	for(int i=head[x];i!=-1;i=nxt[i])	if(to[i]!=fa[0][x])	fa[0][to[i]]=x,dep[to[i]]=dep[x]+1,dfs(to[i]);
}
inline void add(int a,int b)
{
	to[cnt]=b,nxt[cnt]=head[a],head[a]=cnt++;
}
bool cmp(const int &a,const int &b)
{
	return p[a]<p[b];
}
inline int lca(int a,int b)
{
	if(dep[a]<dep[b])	swap(a,b);
	for(int i=Log[dep[a]-dep[b]];i>=0;i--)	if(dep[fa[i][a]]>=dep[b])	a=fa[i][a];
	if(a==b)	return a;
	for(int i=Log[dep[a]];i>=0;i--)	if(fa[i][a]!=fa[i][b])	a=fa[i][a],b=fa[i][b];
	return fa[0][a];
}
void DP(int x)
{
	int y,t0=0,t1=0,t2=0;
	vector<int>::iterator it;
	for(it=ch[x].begin();it!=ch[x].end();it++)
	{
		y=*it,DP(y);
		t2=min(t2+f[y],t0+min(f[y],g[y])),t0+=f[y],t1+=min(f[y],g[y]);
	}
	ch[x].clear();
	if(vis[x]==now)
	{
		g[x]=t0,f[x]=t0+1;
	}
	else
	{
		g[x]=t2,f[x]=min(t1+1,t0);
	}
}
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
	return ret*f;
}
int main()
{
	//freopen("a.in","r",stdin);
	n=rd();
	int i,j,a,b,c;
	memset(head,-1,sizeof(head));
	for(i=2;i<=n;i++)	a=rd(),b=rd(),add(a,b),add(b,a),Log[i]=Log[i>>1]+1;
	dep[1]=1,dfs(1);
	for(j=1;(1<<j)<=n;j++)	for(i=1;i<=n;i++)	fa[j][i]=fa[j-1][fa[j-1][i]];
	m=rd();
	for(now=1;now<=m;now++)
	{
		a=rd();
		for(i=1;i<=a;i++)	A[i]=rd(),vis[A[i]]=now;
		for(i=1;i<=a;i++)	if(vis[fa[0][A[i]]]==now)
		{
			puts("-1");
			break;
		}
		if(i<=a)	continue;
		sort(A+1,A+a+1,cmp);
		st[top=1]=A[1];
		for(i=2;i<=a;i++)
		{
			c=lca(A[i-1],A[i]);
			while(top&&dep[st[top]]>dep[c])
			{
				b=st[top--];
				if(top&&dep[st[top]]>dep[c])	ch[st[top]].push_back(b);
				else	ch[c].push_back(b);
			}
			if(!top||st[top]!=c)	st[++top]=c;
			st[++top]=A[i];
		}
		while(top>1)	ch[st[top-1]].push_back(st[top]),top--;
		DP(st[top]);
		a=min(g[st[top]],f[st[top]]);
		printf("%d\n",a);
	}
	return 0;
}
posted @ 2018-04-05 19:12  CQzhangyu  阅读(719)  评论(0编辑  收藏  举报