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;
}