题意:给你一棵树。q次询问,每次给你一些非关键点,其他的点都是关键点,让你输出树中既不是关键点,也不是关键点的lca的点的数量。

对每次询问的非关键点按照深度从深到浅排序,依次处理,最开始每个点受到的警告次数为零。如果一个点的儿子数-它受到的警告数量>=2(就是它能够从至少2个子树中各取一个关键点,使得它们的lca为它),则该点能成为关键点的lca;如果一个点的儿子数恰好等于它受到的警告数量,则让它父亲的警告次数+1,也就是说它父亲的这个子树废了。

#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
typedef vector<int>::iterator ITER;
int fa[100005],dep[100005],son[100005];
vector<int>G[100005];
bool cmp(const int &a,const int &b){
return dep[a]>dep[b];
}
void dfs(int U){
for(ITER it=G[U].begin();it!=G[U].end();++it){
if(!fa[*it]){
fa[*it]=U;
++son[U];
dep[*it]=dep[U]+1;
dfs(*it);
}
}
}
int T,n,q,m,b[100005],warn[100005];
int main(){
int x,y;
scanf("%d",&T);
for(int zu=1;zu<=T;++zu){
scanf("%d%d",&n,&q);
for(int i=1;i<n;++i){
scanf("%d%d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
fa[1]=-1;
dfs(1);
printf("Case #%d:\n",zu);
for(int i=1;i<=q;++i){
scanf("%d",&m);
for(int j=1;j<=m;++j){
scanf("%d",&b[j]);
}
int ans=0;
sort(b+1,b+m+1,cmp);
for(int j=1;j<=m;++j){
if(!son[b[j]]){
if(b[j]!=1){
++warn[fa[b[j]]];
}
}
else if(son[b[j]]-warn[b[j]]>=2){
++ans;
}
else if(son[b[j]]==warn[b[j]]){
if(b[j]!=1){
++warn[fa[b[j]]];
}
}
}
for(int j=1;j<=m;++j){
if(b[j]!=1){
warn[fa[b[j]]]=0;
}
}
printf("%d\n",n-m+ans);
}
for(int i=1;i<=n;++i){
G[i].clear();
son[i]=fa[i]=0;
}
}
return 0;
}
05-12 08:15