题意:给你一棵树。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: ",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-m+ans); } for(int i=1;i<=n;++i){ G[i].clear(); son[i]=fa[i]=0; } } return 0; }