这是个假题吧...
首先显然上虚树了
然后我们考虑一下最优策略:
如果虚树两节点都是关键点,那么这两点之间至少选一个
如果一个节点本身是关键点,那么我们必须覆盖下下面所有点
如果一个节点本身不是关键点,那么这个点可选可不选,这一点要基于下面有多少个上来来决定
也就是说,我们在虚树上dfs的过程中需要考虑到每个子节点向上会传递多少个节点,也就是说每个节点选最少的情况下可能不能完全封死下面的点,可能会向上传递一些节点,这时我们就需要处理这个问题
但是向上传递一部分节点一定是更优的,因为我们这时只需选一个LCA即可堵住多个节点
因此我们直接讨论:如果当前点不是关键点而底下传上来的点数>1,那么这个点就需要选
如果这个点本身就是关键点,那么就要封上所有底下传上来的点,然后向上传一个点即可
贴代码:
#include <cstdio> #include <cmath> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #include <queue> #include <stack> #include <vector> #include <map> using namespace std; struct Edge { int nxt; int to; }edge[200005]; int head[100005]; int f[100005][25]; int inr[100005],our[100005],dep[100005]; int my_stack[100005],mine_stack[100005]; bool bas[100005],vis[100005]; int dp[100005]; vector <int> v[100005]; map <int,int> acc[100005]; int deep=0; int cnt=1; int n,q,m; void add(int l,int r) { edge[cnt].nxt=head[l]; edge[cnt].to=r; acc[l][r]=1; head[l]=cnt++; } void dfs(int x,int fx) { f[x][0]=fx,inr[x]=++deep,dep[x]=dep[fx]+1; for(int i=1;i<=20;i++)f[x][i]=f[f[x][i-1]][i-1]; for(int i=head[x];i;i=edge[i].nxt) { int to=edge[i].to; if(to==fx)continue; dfs(to,x); } our[x]=++deep; } bool cmp(int x,int y) { return inr[x]<inr[y]; } int LCA(int x,int y) { if(dep[x]>dep[y])swap(x,y); for(int i=20;i>=0;i--)if(dep[f[y][i]]>=dep[x])y=f[y][i]; if(x==y)return x; int ret; for(int i=20;i>=0;i--) { if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i]; else ret=f[x][i]; } return ret; } bool be_in(int x,int y)//y in x { return inr[y]>inr[x]&&our[y]<our[x]; } int redfs(int x) { int temp=0; for(int i=0;i<v[x].size();i++) { int to=v[x][i]; if(bas[x]&&bas[to]&&acc[x][to])return -1; int t=redfs(to); if(t==-1)return -1; temp+=t; dp[x]+=dp[to]; } if(!bas[x]){if(temp>1)temp=0,dp[x]++;} else dp[x]+=temp,temp=1; return temp; } inline int read() { int f=1,x=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int main() { n=read(); for(int i=1;i<n;i++) { int x=read(),y=read(); add(x,y),add(y,x); } dfs(1,1); q=read(); while(q--) { m=read(); for(int i=1;i<=m;i++)my_stack[i]=read(),bas[my_stack[i]]=vis[my_stack[i]]=1; sort(my_stack+1,my_stack+m+1,cmp); int t=m; for(int i=1;i<m;i++) { int fa=LCA(my_stack[i],my_stack[i+1]); if(!vis[fa])vis[fa]=1,my_stack[++t]=fa; } sort(my_stack+1,my_stack+t+1,cmp); int T1=0,rt; for(int i=1;i<=t;i++) { while(T1&&!be_in(mine_stack[T1],my_stack[i]))T1--; if(!T1)rt=my_stack[i]; else v[mine_stack[T1]].push_back(my_stack[i]); mine_stack[++T1]=my_stack[i]; } int tmp=redfs(rt); if(tmp==-1)printf("-1 "); else printf("%d ",dp[rt]); for(int i=1;i<=t;i++)v[my_stack[i]].clear(),dp[my_stack[i]]=bas[my_stack[i]]=vis[my_stack[i]]=0; } return 0; }