CF613D

这是个假题吧...

首先显然上虚树了

然后我们考虑一下最优策略:

如果虚树两节点都是关键点,那么这两点之间至少选一个

如果一个节点本身是关键点,那么我们必须覆盖下下面所有点

如果一个节点本身不是关键点,那么这个点可选可不选,这一点要基于下面有多少个上来来决定

也就是说,我们在虚树上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\n");
        else printf("%d\n",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;
}

 

posted @ 2019-07-07 21:30  lleozhang  Views(204)  Comments(0Edit  收藏
levels of contents