zoukankan      html  css  js  c++  java
  • luogu P2495

    传送门:https://www.luogu.com.cn/problem/P2495

    题意:给你一颗n个点的树,现在的情况是每条边有边权,现在要选取一些点,通过删除一些边的方式使得这些点与1号节点失去连通性,删除一条边的代价是边权大小。有多次询问,保证多次询问的总的点数与n同阶。

      分析:直接去跑树形dp,显然会gg。因为有多次询问,复杂度会达到惊人的(n*q)。一个直观的想法是,如果我们的复杂度只与要询问的点的数量有关的话,或许就没问题了。直接套上虚树再去跑一个树形dp即可。设dp[i]表示,将i子树中所有选中的点与该点断开的代价。显然dp[i]=dp[i]+min(dp[son[i]],weight[e])(son[i]不是被选中的点),dp[i]=dp[i]+weight[e](son[i]是被选中的点)。

    #include<bits/stdc++.h>
    
    #define all(x) x.begin(),x.end()
    #define fi first
    #define sd second
    #define lson (nd<<1)
    #define rson (nd+nd+1)
    #define PB push_back
    #define mid (l+r>>1)
    #define MP make_pair
    #define SZ(x) (int)x.size()
    
    using namespace std;
    
    typedef long long LL;
    
    typedef vector<int> VI;
    
    typedef pair<int,int> PII;
    
    inline int read(){
        int res=0, f=1;char ch=getchar();
        while(ch<'0'|ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();}
        return res*f;
    }
    
    const int MAXN = 1000005;
    
    const int MOD = 1000000007;
    
    void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;}
    int mulmod(int a, int b){return 1ll*a*b%MOD;}
    
    template<typename T>
    void chmin(T& a, T b){if(a>b)a=b;}
    
    template<typename T>
    void chmax(T& a, T b){if(b>a)a=b;}
    
    #define go(e,u) for(int e=head[u];e;e=Next[e])
    int to[MAXN<<1],Next[MAXN<<1],head[MAXN],tol;
    LL dis[MAXN<<1];
    
    void add_edge(int u,int v,int val){
        Next[++tol]=head[u];to[tol]=v;head[u]=tol;dis[tol]=val;
        Next[++tol]=head[v];to[tol]=u;head[v]=tol;dis[tol]=val;
    }
    
    #define gov(e,u) for(int e=headv[u];e;e=Nextv[e])
    int tov[MAXN<<1],Nextv[MAXN<<1],headv[MAXN],tolv;
    
    void add_edgev(int u,int v){
        Nextv[++tolv]=headv[u];tov[tolv]=v;headv[u]=tolv;
    }
    
    LL minv[MAXN];
    
    int n, h[MAXN], mark[MAXN];
    
    int dep[MAXN],up[MAXN][25],dfn[MAXN],dfncnt;
    
    int st[MAXN], top;
    
    bool cmp(int x, int y){
        return dfn[x]<dfn[y];
    }
    
    void dfs(int u,int f){
        dfn[u]=++dfncnt;
        for(int i=0;up[u][i];++i)up[u][i+1]=up[up[u][i]][i];
    
        go(e,u){
            int v=to[e];
            if(v==f)continue;
            dep[v]=dep[u]+1;up[v][0]=u;
            minv[v]=min(minv[u],dis[e]);
            dfs(v,u);
        }
    }
    
    int getLCA(int u, int v){
        if(dep[u]<dep[v]) swap(u,v);
    
        for(int i=20;i>=0;--i){
            if(dep[up[u][i]]>=dep[v]){
                u=up[u][i];
            }
        }
    
        if(u==v)return u;
    
        for(int i=20;i>=0;--i){
            if(up[u][i]!=up[v][i]){
                u=up[u][i];
                v=up[v][i];
            }
        }
    
        return up[u][0];
    }
    
    LL dfs1(int u){
        LL ret=0;LL s=0;
    
        gov(e,u){
            int v=tov[e];
            s+=dfs1(v);
        }
    
        if(mark[u])ret=minv[u];
        else ret=min(minv[u],s);
    
        return ret;
    }
    
    int main(){
        minv[1]=1e18;
    
        n=read();
        for(int i=1;i<n;++i){
            int u,v,val;
            u=read();v=read();val=read();
            add_edge(u,v,val);
        }
    
        dfs(1,0);
    
        int q=read();
        while(q--){
            int cnt=read();
            for(int i=1;i<=cnt;++i){
                h[i]=read();
                mark[h[i]]=1;
            }
    
            sort(h+1,h+cnt+1,cmp);
            //建立虚树
            st[top=1]=1;tolv=0;headv[1]=0;
            for(int i=1;i<=cnt;++i){
                if(h[i]!=1){
                    int l=getLCA(h[i],st[top]);
                    if(l!=st[top]){
                        while(dfn[l]<dfn[st[top-1]]){
                            add_edgev(st[top-1],st[top]);
                            --top;
                        }
                        if(dfn[l]>dfn[st[top-1]]){
                            headv[l]=0;add_edgev(l,st[top]);st[top]=l;
                        }else{
                            add_edgev(l,st[top--]);
                        }
                    }
                    headv[h[i]]=0;st[++top]=h[i];
                }
            }
    
            for(int i=1;i<top;++i)add_edgev(st[i],st[i+1]);
            cout<<dfs1(st[1])<<endl;
            for(int i=1;i<=cnt;++i)mark[h[i]]=0;
    
        }
    
        return 0;
    }
    View Code
  • 相关阅读:
    javascript基础案例解析
    Javascript正则
    Javascript数组
    JS函数
    数据类型转换
    flex弹性布局
    css基础5
    css基础4
    场景化支付对现有技术、业务、产品和风险产生深刻的影响
    场景化支付的关键技术
  • 原文地址:https://www.cnblogs.com/JohnRan/p/12767320.html
Copyright © 2011-2022 走看看