CF613D Kingdom and its Cities

【题意】

【分析】

 

首先特判掉无解的情况,也就是选了x和fa[x]的情况

 

然后我们可以建立虚树,给指定的k个点设置点权为1(为了区分lca)

 

设f[x]为以x为子树的答案,g[x]为这个点及其子树内是否有需要被割的点

 

考虑这个点是不是关键点,如果是原来给定的点,f[x]+=g[xson],也就是让他的所有需要被断开的儿子都断开

 

如果这个点不是关键点,那么我们考虑如果他有多个儿子都需要被断开,那就把这个点断开f[x]+=1,如果只有一个就让g[x]=1,向上传递等待被断

 

一定记得在dfsdp的时候清零head否则会锅:(

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int n,q,m,tot,head[maxn],nh[maxn],etot;
struct edge
{
    int to,nxt;
}e[maxn<<1],ne[maxn<<1];
void add(int x,int y)
{
    e[++tot].to=y; e[tot].nxt=head[x]; head[x]=tot;
}
void addedge(int x,int y)
{
    ne[++etot].to=y; ne[etot].nxt=nh[x]; nh[x]=etot;
}
int f[maxn][20],dep[maxn],vis[maxn],qu[maxn];
int dfn[maxn],dfstime,st[maxn],top;
void dfs(int u,int fa)
{
    f[u][0]=fa; dep[u]=dep[fa]+1;
    dfn[u]=++dfstime;
    for(int i=head[u];i;i=e[i].nxt)
    {
        int to=e[i].to;
        if(to==fa) continue;
        dfs(to,u);
    }
}
void lca_init()
{
    for(int j=1;j<=18;j++)
        for(int i=1;i<=n;i++)
            f[i][j]=f[f[i][j-1]][j-1];
}
bool cmp(int a,int b)
{
    return dfn[a]<dfn[b];
}
int getlca(int x,int y)
{
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=18;i>=0;i--)
        if(dep[f[x][i]]>=dep[y])
            x=f[x][i];
    if(x==y) return x;
    for(int i=18;i>=0;i--)
        if(f[x][i]!=f[y][i])
            x=f[x][i],y=f[y][i];
    return f[x][0];
}
int g[maxn];
int dfsdp(int u)
{
    int ucnt=0,uneed=0;
    for(int i=nh[u];i;i=ne[i].nxt)
    {
        int to=ne[i].to;
        ucnt+=dfsdp(to);
        uneed+=g[to];
    }
    if(vis[u]) ucnt+=uneed,g[u]=1;
    else if(uneed>1) ucnt++,g[u]=false;
    else g[u]=uneed?1:0;
    vis[u]=0; nh[u]=0;
    return ucnt;
}
int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    scanf("%d",&n);
    int x,y;
    for(int i=1;i<n;i++)    
    {
        scanf("%d%d",&x,&y);
        add(x,y); add(y,x);
    }
    dfs(1,0); lca_init();
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&q);
        bool flag=0; etot=0;
        for(int j=1;j<=q;j++)
        {
            scanf("%d",&qu[j]);
            vis[qu[j]]=1;
        }
        for(int j=1;j<=q;j++)
            if(vis[f[qu[j]][0]]) flag=1;
        if(flag)
        {
            for(int j=1;j<=q;j++)
                vis[qu[j]]=0;
            printf("-1\n");
            continue;
        }
        sort(qu+1,qu+q+1,cmp);
        st[top=1]=qu[1];
        for(int i=2;i<=q;i++)
        {
            int z=getlca(qu[i],st[top]);
            while(dep[st[top-1]]>dep[z])
            {
                addedge(st[top-1],st[top]);
                top--;
            }
            if(st[top]!=z)
            {
                addedge(z,st[top]);
                if(st[top-1]==z) top--;
                else st[top]=z;
            }
            st[++top]=qu[i];
        }
        while(--top) addedge(st[top],st[top+1]);
        printf("%d\n",dfsdp(st[1]));
    }
    return 0;
}

 

posted @ 2021-05-21 08:06  andyc_03  阅读(43)  评论(0编辑  收藏  举报