CF613D Kingdom and its Cities(虚树)

通过领悟题意,发现本题只与关键点和他们的lca有关,因此把只需要对他们建虚树

对于dp思路,如果x不是关键点,那么观察子树中有多少需要断开的,如果超过1,那么直接断开这个点,如果等于1,先保留看看能否与后面的一起。

如果是关键点,那就必须要把当前点和子树中的所有关键点断开,首先我们知道一定存在合法方案,因为不存在的已经特判过了,所以只需记录子树中的个数即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+10;
const int mod=998244353;
vector<int> g1[N],g[N];
int dfn[N],times,f[N][25],st[N],depth[N];
int cnt[N],q[N],d[N],sign[N];
int vis[N];
void dfs(int u,int fa){
    depth[u]=depth[fa]+1;
    dfn[u]=++times;
    int i;
    f[u][0]=fa;
    for(i=1;i<=21;i++){
        f[u][i]=f[f[u][i-1]][i-1];
    }
    for(i=0;i<g1[u].size();i++){
        int v=g1[u][i];
        if(v==fa)
            continue;
        dfs(v,u);
    }
}
bool cmp(int x,int y){
    return dfn[x]<dfn[y];
}
int lca(int a,int b){
    if(depth[a]<depth[b])
        swap(a,b);
    int i;
    for(i=21;i>=0;i--){
        if(depth[f[a][i]]>=depth[b]){
            a=f[a][i];
        }
    }
    if(a==b)
        return a;
    for(i=21;i>=0;i--){
        if(f[a][i]!=f[b][i]){
            a=f[a][i];
            b=f[b][i];
        }
    }
    return f[a][0];
}
void add(int a,int b){
    g[a].push_back(b);
}
void get(int u){
    int i;
    int cnt=0;
    for(i=0;i<g[u].size();i++){
        int v=g[u][i];
        get(v);
        d[u]+=d[v];
        if(st[u]){
            d[u]+=sign[v];
        }
        else{
            if(sign[v])
                cnt++;
        }
        d[v]=0,st[v]=0,sign[v]=0,vis[v]=0;
    }
    if(!st[u]){
        if(cnt>1){
            d[u]++;
        }
        else if(cnt==1){
            sign[u]=1;
        }
    }
    g[u].clear();
}
int main(){
    ios::sync_with_stdio(false);
    int n;
    cin>>n;
    int i;
    for(i=1;i<n;i++){
        int a,b;
        cin>>a>>b;
        g1[a].push_back(b);
        g1[b].push_back(a);
    }
    dfs(1,0);
    int t;
    cin>>t;
    while(t--){
        int k;
        cin>>k;
        for(i=1;i<=k;i++){
            int x;
            cin>>x;
            st[x]=1;
            cnt[i]=x;
            sign[x]=1;
            vis[x]=1;
        }
        int kk=0;
        for(i=1;i<=k;i++){
            if(vis[f[cnt[i]][0]]){
                kk=1;
                break;
            }
        }
        if(kk){
            for(i=1;i<=k;i++){
                vis[cnt[i]]=0;
                sign[cnt[i]]=0;
                st[cnt[i]]=0;
            }
            cout<<-1<<endl;
            continue;
        }
        sort(cnt+1,cnt+1+k,cmp);
        q[1]=1;
        int tt=1;
        for(i=1;i<=k;i++){
            if(cnt[i]==1)
                continue;
            int p=lca(cnt[i],q[tt]);
            if(p!=q[tt]){
                while(dfn[p]<dfn[q[tt-1]]){
                    add(q[tt-1],q[tt]);
                    tt--;
                }
                if(dfn[p]!=dfn[q[tt-1]]){
                    add(p,q[tt]);
                    q[tt]=p;
                }
                else{
                    add(p,q[tt]);
                    tt--;
                }
            }
            q[++tt]=cnt[i];
        }
        for(i=1;i<tt;i++){
            add(q[i],q[i+1]);
        }
        get(1);
        cout<<d[1]<<endl;
        d[1]=0,sign[1]=0,st[1]=0,vis[1]=0;
    }
    return 0;
}
View Code

 

posted @ 2020-07-22 20:32  朝暮不思  阅读(155)  评论(0编辑  收藏  举报