【CF613D】 Kingdom and its Cities

题目

题目描述
Meanwhile, the kingdom of K is getting ready for the marriage of the King’s daughter. However, in order not to lose face in front of the relatives, the King should first finish reforms in his kingdom. As the King can not wait for his daughter’s marriage, reforms must be finished as soon as possible.

The kingdom currently consists of nn cities. Cities are connected by n-1n−1 bidirectional road, such that one can get from any city to any other city. As the King had to save a lot, there is only one path between any two cities.

What is the point of the reform? The key ministries of the state should be relocated to distinct cities (we call such cities important). However, due to the fact that there is a high risk of an attack by barbarians it must be done carefully. The King has made several plans, each of which is described by a set of important cities, and now wonders what is the best plan.

Barbarians can capture some of the cities that are not important (the important ones will have enough protection for sure), after that the captured city becomes impassable. In particular, an interesting feature of the plan is the minimum number of cities that the barbarians need to capture in order to make all the important cities isolated, that is, from all important cities it would be impossible to reach any other important city.

Help the King to calculate this characteristic for each of his plan.

输入格式
The first line of the input contains integer nn ( 1<=n<=1000001<=n<=100000 ) — the number of cities in the kingdom.

Each of the next n-1n−1 lines contains two distinct integers u_{i}u
i

, v_{i}v
i

( 1<=u_{i},v_{i}<=n1<=u
i

,v
i

<=n ) — the indices of the cities connected by the ii -th road. It is guaranteed that you can get from any city to any other one moving only along the existing roads.

The next line contains a single integer qq ( 1<=q<=1000001<=q<=100000 ) — the number of King’s plans.

Each of the next qq lines looks as follows: first goes number k_{i}k
i

— the number of important cities in the King’s plan, ( 1<=k_{i}<=n1<=k
i

<=n ), then follow exactly k_{i}k
i

space-separated pairwise distinct numbers from 1 to nn — the numbers of important cities in this plan.

The sum of all k_{i}k
i

's does’t exceed 100000100000 .

输出格式
For each plan print a single integer — the minimum number of cities that the barbarians need to capture, or print -1−1 if all the barbarians’ attempts to isolate important cities will not be effective.

题意翻译
一个王国有n座城市,城市之间由n-1条道路相连,形成一个树结构,国王决定将一些城市设为重要城市。

这个国家有的时候会遭受外敌入侵,重要城市由于加强了防护,一定不会被占领。而非重要城市一旦被占领,这座城市就不能通行。

国王定了若干选择重要城市的计划,他想知道,对于每个计划,外敌至少要占领多少个非重要城市,才会导致重要城市之间两两不连通。如果外敌无论如何都不可能导致这种局面,输出-1

感谢@litble 提供的翻译

输入输出样例
输入 #1复制
4
1 3
2 3
4 3
4
2 1 2
3 2 3 4
3 1 2 4
4 1 2 3 4
输出 #1复制
1
-1
1
-1
输入 #2复制
7
1 2
2 3
3 4
1 5
5 6
5 7
1
4 2 4 6 7
输出 #2复制
2
说明/提示
In the first sample, in the first and the third King’s plan barbarians can capture the city 3, and that will be enough. In the second and the fourth plans all their attempts will not be effective.

In the second sample the cities to capture are 3 and 5.

思路

虚树+dp
不妨设当前节点为x,temp为F[x],bj数组表示某个点是不是关键点
1.如果x是关键节点,那么如果他的儿子也是关键节点,temp+=dp(儿子)+1即可,如果他的儿子是非关键节点(也就是一个lca点),那么我们把要考虑的情况扔给这个lca点,在当前层直接temp+=dp(儿子)。
注意,如果x和他的儿子都是关键节点,要特判在原树中有没有父子关系(具体就是特判一下深度即可),有的话打个标记在这次询问直接输出-1
2.如果x是非关键节点,也就是x是某个lca,我们考虑他的各个子树,如果有大于一个子树能传递上来关键点,很显然x点必须封堵,那么return temp+1。如果只有一个子树能传递上来关键点,那么lca号点不必封堵,直接将这个关键点信息继续向上传递。如果没有子树能传递上来关键点,就什么也不用管。
那么如何表示这个传递关键点操作?
直接开一个数组g,在遍历x号点的儿子时加上这样一句:
if(g[e[x][i]]||bj[e[x][i]]) t++; //t表示有几个子树能传递关键点
即可判断传递信息的子树个数,然后在t1时,g[x]设为1即可。
注意要特判当x为非关键节点时,t
1并且在虚树中x的父亲是关键节点时,直接返回temp+1(这就是前文提到的“把要考虑的情况扔给这个lca点”)

代码

#include<bits/stdc++.h>
using namespace std;
#define N 200010
int a[N],stop,stac[N],vist,dfn[N],h[N],cnt,top[N],siz[N],son[N],dep[N],fa[N],st[N],n,m,q,ans,ance;
struct node { int y,next; }edg[N<<1];
bool cmp(int x,int y) { return dfn[x]<dfn[y]; }
void add(int x,int y) { edg[++cnt].next=h[x],edg[cnt].y=y,h[x]=cnt; }
void dfs1(int x,int fat){
	siz[x]=1;
	for(int i=h[x];i;i=edg[i].next) {
		int y=edg[i].y;if(y==fat) continue;
		dep[y]=dep[fa[y]=x]+1,dfs1(y,x),siz[x]+=siz[y];
		if(siz[son[x]]<siz[y]) son[x]=y;
	}
}
void dfs2(int x) {
	dfn[x]=++vist;
	if(!son[x]) return;
	top[son[x]]=top[x],dfs2(son[x]);
	for(int i=h[x];i;i=edg[i].next) {
		int y=edg[i].y;if(y==fa[x]||y==son[x]) continue;
		dfs2(top[y]=y);
	}
}
int lca(int x,int y) {
	while(top[x]^top[y]) {
		if(dep[top[x]]>dep[top[y]]) x=fa[top[x]];
		else y=fa[top[y]];
	}
	if(dep[x]<dep[y]) return x;return y;
}
void ins(int x) {
	if(!stop) { stac[stop=1]=x;return; }
	int anc=lca(stac[stop],x);
	while(stop&&dep[anc]<dep[stac[stop]]) add(stac[stop-1],stac[stop]),--stop;
	if(!stop||stac[stop]!=anc) stac[++stop]=anc;
	stac[++stop]=x;
}
void dfs3(int x) {
	if(siz[x]) {
		for(int i=h[x];i;i=edg[i].next) {
			int y=edg[i].y;dfs3(y);
			if(siz[y]) siz[y]=0,++ans;
		}
	}
	else {
		for(int i=h[x];i;i=edg[i].next) {
			int y=edg[i].y;
			dfs3(y),siz[x]+=siz[y],siz[y]=0;
		}
		if(siz[x]>1) ++ans,siz[x]=0;
	}
	h[x]=0;
}
int main() {
	n=read();
	for(int i=1;i<n;++i) {
		int x=read(),y=read();
		add(x,y),add(y,x);
	}
	dfs1(dep[1]=1,0),dfs2(top[1]=1),q=read(),vist=0;;
	memset(h,0,sizeof(h)),memset(siz,0,sizeof(siz));
	for(int i=1;i<=q;++i) {
		int x=1;m=read();
		for(int i=1;i<=m;++i) a[i]=read(),siz[a[i]]=1;
		for(int i=1;i<=m;++i) if(siz[fa[a[i]]]) { printf("-1\n"),x=0;break; }
		if(!x) { while(m) siz[a[m]]=0,--m;continue; }
		ans=0,sort(a+1,a+m+1,cmp);
		if(a[1]!=1) stac[stop=1]=1;
		for(int i=1;i<=m;++i) ins(a[i]);
		if(stop) while(--stop) add(stac[stop],stac[stop+1]);
		dfs3(1),siz[1]=vist=0,printf("%d\n",ans);
	} 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值