CF613D Kingdom and its Cities

题目描述:

luogu

cf

题解:

虚树上dp。

建虚树没啥说的。

那么dp状态?

考虑dfs时返回一个值,代表这个子树上面需不需要隔断。

如果当前点可以占,那么有至少两个这种子树时应该选这个点并返回0,要不然返回1;

如果不能占,直接加到dp值上,然后返回1即可。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 100050;
template<typename T>
inline void read(T&x)
{
    T f = 1,c = 0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
    x = f*c;
}
int n,Q,hed[N],cnt,Hed[N],Cnt;
struct EG
{
    int to,nxt;
}e[N<<1],E[N];
void ae(int f,int t)
{
    e[++cnt].to = t;
    e[cnt].nxt = hed[f];
    hed[f] = cnt;
}
void aE(int f,int t)
{
    E[++Cnt].to = t;
    E[Cnt].nxt = Hed[f];
    Hed[f] = Cnt;
}
int sta[N],tl,Sta[N],Tl,rt,k[N];
bool vis[N],use[N];
int dep[N],tin[N],siz[N],son[N],tout[N],fa[N],tim,top[N];
bool cmp(int x,int y){return tin[x]<tin[y];}
bool fs(int x,int y){return tin[x]<tin[y]&&tout[x]>=tout[y];}
void dfs1(int u,int f)
{
    fa[u] = f,siz[u] = 1,dep[u] = dep[f]+1;
    for(int j=hed[u],to;j;j=e[j].nxt)
        if((to=e[j].to)!=f)
        {
            dfs1(to,u);siz[u]+=siz[to];
            if(siz[son[u]]<siz[to])son[u]=to;
        }
}
void dfs2(int u,int Top)
{
    top[u] = Top,tin[u] = ++tim;
    if(son[u])dfs2(son[u],Top);
    for(int j=hed[u],to;j;j=e[j].nxt)
        if((to=e[j].to)!=fa[u]&&to!=son[u])
            dfs2(to,to);
    tout[u] = tim;
}
int get_lca(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        x = fa[top[x]];
    }
    return dep[x]<dep[y]?x:y;
}
int dp[N];
int dfs(int u)
{
    int tmp = 0;
    for(int j=Hed[u],to;j;j=E[j].nxt)
    {
        to = E[j].to;
        tmp+=dfs(to);
        dp[u]+=dp[to];
    }
    if(!use[u])
    {
        if(tmp>1)dp[u]++,tmp=0;
    }else dp[u]+=tmp,tmp=1;
    return tmp;
}
void clear()
{
    for(int i=1,u;i<=tl;i++)
    {
        u = sta[i];
        vis[u]=use[u]=0;
        Hed[u]=dp[u]=0;
    }
    tl=Tl=Cnt=0;
}
int main()
{
//    freopen("tt.in","r",stdin);
    read(n);
    for(int u,v,i=1;i<n;i++)
    {
        read(u),read(v);
        ae(u,v),ae(v,u);
    }
    dfs1(1,0),dfs2(1,1);
    read(Q);
    for(int m,i=1;i<=Q;i++)
    {
        read(m);tl = m;
        for(int j=1,x;j<=m;j++)read(x),vis[x]=use[x]=1,sta[j]=x;
        sort(sta+1,sta+1+m,cmp);
        for(int j=1,x;j<m;j++)
            if(!vis[x=get_lca(sta[j],sta[j+1])])
                vis[x]=1,sta[++tl]=x;
        sort(sta+1,sta+1+tl,cmp);
        rt = sta[1];Sta[Tl=1]=rt;
        bool FG = 0;
        for(int j=2;j<=tl;j++)
        {
            while(Tl&&!fs(Sta[Tl],sta[j]))Tl--;
            Sta[++Tl] = sta[j];
            if(fa[sta[j]]==Sta[Tl-1]&&use[Sta[Tl-1]]&&use[sta[j]])FG=1;
            aE(Sta[Tl-1],sta[j]);
        }
        if(FG){puts("-1");}
        else
        {
            dfs(rt);
            printf("%d\n",dp[rt]);
        }
        clear();
    }
    return 0;
}
View Code

 

posted @ 2019-07-07 21:14  LiGuanlin  阅读(227)  评论(0编辑  收藏  举报