zoukankan      html  css  js  c++  java
  • 虚树的学习

    虚树的学习

    学习博客:https://www.cnblogs.com/chenhuan001/p/5639482.html

    模板题目:https://darkbzoj.tk/problem/2286

    模板:https://www.cnblogs.com/Orz-IE/p/12149366.html

    题目博客:https://blog.csdn.net/ez_2016gdgzoi471/article/details/78844732

    D. Kingdom and its Cities

    这个题目难点就是想到虚树,然后就是一个树形dp (dp[i][j])

    • (j==1) 表示有点从 (i) 这棵子树出来
    • (j==0) 表示没有点从 (i) 这棵子树出来
    #include <bits/stdc++.h>
    #define inf 0x3f3f3f3f
    #define debug(x) printf("debug:%s=%d
    ",#x,x);
    //#define debug(x) cout << #x << ": " << x << endl
    //快读,需要文件读入
    # define getchar() (S==T&&(T=(S=BB)+fread(BB,1,1<<20,stdin),S==T)?EOF:*S++)
    char BB[1 << 20], *S = BB, *T = BB;
    int read()
    {
        int x=0;
        char c=getchar();
        while (!isdigit(c)) c=getchar();
        while (isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
        return x;
    }
    using namespace std;
    const int maxn = 1e5+10;
    typedef long long ll;
    int head[maxn<<1],nxt[maxn<<1],to[maxn<<1],cnt;
    void ADD(int u,int v){
    //    printf("u=%d v=%d
    ",u,v);
        ++cnt,to[cnt]=v,nxt[cnt]=head[u],head[u]=cnt;
        ++cnt,to[cnt]=u,nxt[cnt]=head[v],head[v]=cnt;
    }
    int dfn[maxn],dep[maxn],siz[maxn],fa[maxn],top[maxn],son[maxn],tim;
    void dfs1(int u){
        siz[u]=1;
        dep[u]=dep[fa[u]]+1;
        for(int i=head[u];i;i=nxt[i]){
            int v = to[i];
            if(v==fa[u]) continue;
            fa[v]=u;
            dfs1(v);
            siz[u]+=siz[v];
            if(!son[u]||siz[son[u]]<siz[v]) son[u]=v;
        }
    }
    void dfs2(int u,int tp){
        dfn[u]=++tim,top[u]=tp;
        if(!son[u]) return ;
        dfs2(son[u],tp);
        for(int i=head[u];i;i=nxt[i]){
            int v = to[i];
            if(v==fa[u]||v==son[u]) continue;
            dfs2(v,v);
        }
    }
    int Lca(int u,int v) {
        while (top[u] != top[v]) {
            if (dep[top[u]] < dep[top[v]]) swap(u, v);
            u = fa[top[u]];
        }
        return dep[u] > dep[v] ? v : u;
    }
    int stk[maxn],cur;
    void insert(int p){
    //    printf("p=%d
    ",p);
        int x = stk[cur];
        if(x==1){stk[++cur]=p;return;}
        int lca = Lca(p,x);
        while(lca!=stk[cur]){
            int y = stk[--cur];
            if(dfn[y]<dfn[lca]){
                ADD(lca,x),stk[++cur]=lca;
                break;
            }
            ADD(x,y),x=stk[cur];
        }
        stk[++cur]=p;
    }
    
    int c[maxn],have[maxn];
    bool cmp(const int& a,const int& b){
        return dfn[a]<dfn[b];
    }
    
    ll dp[maxn][2],a[maxn];
    void DP(int u,int pre){
        siz[u]=have[u];
        if(have[u]) dp[u][0]=inf,dp[u][1]=0;
        else dp[u][0]=0,dp[u][1]=0;
        for(int i=head[u];i;i=nxt[i]){
            int v = to[i];
            if(v==pre) continue;
            DP(v,u);
        }
        if(have[u]){
            for(int i=head[u];i;i=nxt[i]){
                int v = to[i];
                if(v==pre) continue;
                if(siz[v]&&dep[v]-dep[u]>1) dp[u][1]+=dp[v][1]+1;
                else dp[u][1]+=dp[v][0];
            }
        }
        else{
            int now=0;
            ll ans1=0,ans2=0;
            for(int i=head[u];i;i=nxt[i]){
                int v = to[i];
                if(v==pre) continue;
                ans2+=dp[v][0];
                ans1+=min(dp[v][0],dp[v][1]);
                a[++now]=dp[v][1]-dp[v][0];
            }
            dp[u][0]=min(ans2,ans1+1);
            sort(a+1,a+1+now);
            dp[u][1]+=ans2+a[1];
        }
        have[u]=head[u]=0;
    }
    
    void solve(){
        int k = read();
    //    debug(k);
        cnt=0,stk[cur=1]=1;
        for(int i=1;i<=k;i++) c[i]=read(),have[c[i]]=1;
        sort(c+1,c+1+k,cmp);
        if(c[1]!=1) stk[++cur]=c[1];
        for(int i=2;i<=k;i++) insert(c[i]);
        while(--cur) ADD(stk[cur],stk[cur+1]);
        DP(1,0);
        ll ans = min(dp[1][0],dp[1][1]);
        if(ans>=inf) printf("-1
    ");
        else printf("%lld
    ",ans);
        return ;
    }
    
    int main() {
    //    freopen("1.in", "r", stdin);
        int n = read();
        for (int i = 1; i < n; i++) {
            int u = read(), v = read();
            ADD(u, v);
        }
        dfs1(1),dfs2(1,1);
        memset(head,0,sizeof(head));
        int m = read();
        while (m--) solve();
        return 0;
    }
    

    附录:

    虚树还是很简单的,但是要找到自己喜欢习惯的码风板子。

    typedef long long ll;
    int head[maxn<<1],nxt[maxn<<1],to[maxn<<1],cnt;
    void ADD(int u,int v){
    //    printf("u=%d v=%d
    ",u,v);
        ++cnt,to[cnt]=v,nxt[cnt]=head[u],head[u]=cnt;
        ++cnt,to[cnt]=u,nxt[cnt]=head[v],head[v]=cnt;
    }
    int dfn[maxn],dep[maxn],siz[maxn],fa[maxn],top[maxn],son[maxn],tim;
    void dfs1(int u){
        siz[u]=1;
        dep[u]=dep[fa[u]]+1;
        for(int i=head[u];i;i=nxt[i]){
            int v = to[i];
            if(v==fa[u]) continue;
            fa[v]=u;
            dfs1(v);
            siz[u]+=siz[v];
            if(!son[u]||siz[son[u]]<siz[v]) son[u]=v;
        }
    }
    void dfs2(int u,int tp){
        dfn[u]=++tim,top[u]=tp;
        if(!son[u]) return ;
        dfs2(son[u],tp);
        for(int i=head[u];i;i=nxt[i]){
            int v = to[i];
            if(v==fa[u]||v==son[u]) continue;
            dfs2(v,v);
        }
    }
    int Lca(int u,int v) {
        while (top[u] != top[v]) {
            if (dep[top[u]] < dep[top[v]]) swap(u, v);
            u = fa[top[u]];
        }
        return dep[u] > dep[v] ? v : u;
    }
    int stk[maxn],cur;
    void insert(int p){
    //    printf("p=%d
    ",p);
        int x = stk[cur];
        if(x==1){stk[++cur]=p;return;}
        int lca = Lca(p,x);
        while(lca!=stk[cur]){
            int y = stk[--cur];
            if(dfn[y]<dfn[lca]){
                ADD(lca,x),stk[++cur]=lca;
                break;
            }
            ADD(x,y),x=stk[cur];
        }
        stk[++cur]=p;
    }
    
    int c[maxn],have[maxn];
    bool cmp(const int& a,const int& b){
        return dfn[a]<dfn[b];
    }
    
    ll dp[maxn][2],a[maxn];
    void DP(int u,int pre){
    }
    
    void solve(){
        int k = read();
    //    debug(k);
        cnt=0,stk[cur=1]=1;
        for(int i=1;i<=k;i++) c[i]=read(),have[c[i]]=1;
        sort(c+1,c+1+k,cmp);
        if(c[1]!=1) stk[++cur]=c[1];
        for(int i=2;i<=k;i++) insert(c[i]);
        while(--cur) ADD(stk[cur],stk[cur+1]);
        DP(1,0);
        ll ans = min(dp[1][0],dp[1][1]);
        if(ans>=inf) printf("-1
    ");
        else printf("%lld
    ",ans);
        return ;
    }
    
    
  • 相关阅读:
    bzoj2115: [Wc2011] Xor
    bzoj2844: albus就是要第一个出场
    hdu3949
    bzoj2487: Super Poker II
    bzoj3456: 城市规划
    bzoj3992: [SDOI2015]序列统计
    ubuntu 使用命令行登录oracle
    ubuntu安装docker
    linux查询硬件信息
    ubuntu oracle 环境搭建
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/13330893.html
Copyright © 2011-2022 走看看