CF613D Kingdom and its Cities题解

CF613D Kingdom and its Cities

题意:

一棵 \(n\) 个节点的树,\(m\) 次询问,每次给出\(k\)个点,询问将 \(k\) 个点两两间隔开所需标记的最小间隔点数,若不能间隔开,输出-1。\(n \leq 10^5,\sum k\leq n\)

思路:

观察数据范围,建虚树。DP写错WA了几发。怎么做DP?由于关键点不能标记,所以同样分类讨论。设 \(f_u\) 表示使得以u为根的子树内的点不连通,所需的点数。\(g_u\)表示该子树内有几个点和父亲直接联通--中间未被阻断。如果是关键点,则必须把子树内直接联通的点都切掉,也就是\(f_u=\sum f_v+\sum g_v\),同时\(g_u=1\)。若不是关键点,当子树内有>1g个节点与它直接相连,也就是 \(1 \leq g_u\) 时,我们必须把这个点断掉(要不然这几个点就通过该点连起来了),也就是\(f_u=\sum f_v+1,g_u=0\)

code:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define fo(a,i,b) for(ll i = (a) ; i <= (b) ; ++ i )
#define Fo(a,i,b) for(ll i = (a) ; i >= (b) ; -- i )
#define mms(a2,b2) memset(a2,b2,sizeof(a2))
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int N=2e5+5;
int n,q;
struct node{
	int v,nxt,w;
}e[N<<1],e2[N<<1];
int h[N],tot;
int h2[N],tot2;
int fa[N][20],dfn[N],dep[N],cnt;
int sp[N<<1],fl[N<<1],xu[N<<1];
int frm[N<<1],frw[N<<1];
int f[N<<1],siz[N<<1];\\siz就是题目里说的g
int flag=0;
int read(){int x=0,ff=1;char c=getchar();while(c<'0'||c>'9'){c=getchar();}while(c>='0'&&c<='9'){	x=(x<<1)+(x<<3)+(c^48);	c=getchar();}return x;}
void add(int x,int y){
	e[++tot].nxt=h[x];
	e[tot].v=y;
	h[x]=tot;
}
void add2(int x,int y){
	e2[++tot2].nxt=h2[x];
	e2[tot2].v=y;
	h2[x]=tot2;
}
void dfs(int u,int u_fa){
	fa[u][0]=u_fa;
	dep[u]=dep[u_fa]+1;
	dfn[u]=++cnt;
	for(int i=h[u];~i;i=e[i].nxt){
		int v=e[i].v;
		if(v==u_fa) continue;
		dfs(v,u);
	}
}
void fa_fa(){
	fo(1,i,19)
		fo(1,j,n)
			fa[j][i]=fa[fa[j][i-1]][i-1];
		
}
int lca(int x,int y){
	if(dep[x]<dep[y]) swap(x,y);
	Fo(19,i,0){
		if(dep[fa[x][i]]>=dep[y]) x=fa[x][i];	
	}
	if(x==y) return x;
	Fo(19,i,0){
		if(fa[x][i]!=fa[y][i]){
			x=fa[x][i],y=fa[y][i];
		}
	}
	return fa[x][0];
}
bool cmp(int x,int y){return dfn[x]<dfn[y];}
void solve(int u,int u_fa){
    f[u]=siz[u]=0;
    for(int i=h2[u];~i;i=e2[i].nxt){
        int v=e2[i].v;
        solve(v,u);
        f[u]+=f[v];
        siz[u]+=siz[v];
    }
    if(fl[u]) {
        f[u]+=siz[u];
        siz[u]=1;
    }else if(siz[u]>1){
        f[u]++;
        siz[u]=0;
    }
	h2[u]=-1,fl[u]=0;
 } 
int main(){
	mms(h,-1);
	mms(h2,-1);
	n=read();
	fo(1,i,n-1){
		int x,y;
		x=read(),y=read();
		add(x,y),add(y,x);
	}
	dfs(1,0);
	fa_fa();
	q=read();
	while(q--){
		flag=0;
		int k;
		k=read();
		fo(1,i,k){
			sp[i]=read();
			fl[sp[i]]=1;
		}
		int len=0;
		sort(sp+1,sp+1+k,cmp);
		fo(1,i,k-1){
			xu[++len]=sp[i];
			xu[++len]=lca(sp[i],sp[i+1]);
		}
		xu[++len]=sp[k];
		sort(xu+1,xu+1+len,cmp);
		len=unique(xu+1,xu+1+len)-xu-1;
		fo(1,i,len-1){
			int lc=lca(xu[i],xu[i+1]);
			add2(lc,xu[i+1]);//add2(xu[i+1],lc);
		}
		 if(xu[1]!=1)
       	 add2(1,xu[1]);
		fo(1,i,k){
			if(fl[fa[sp[i]][0]])flag=1;
		}
		if(flag) {
			fo(1,i,tot2) h2[i]=-1;
			printf("-1\n");
		}
		else {
			solve(1,0);
			printf("%d\n",f[1]);	
		}
		fo(1,i,k) fl[sp[i]]=0;
	}
	return 0;
} 
posted @ 2025-05-29 18:08  MoYujing  阅读(8)  评论(0)    收藏  举报