zoukankan      html  css  js  c++  java
  • 【Luogu】P4103大工程(虚树DP)

      题目链接

      我貌似发现这类DP就是先别管什么虚树……把树形DP搞出来套上虚树板子就好了

      这个树形DP就是设sum为答案,sumd为子树内所有点的深度和(当然指的是被询问的点),maxi指子树内最深的点的深度,mini同理

      然后考虑我们dfs到x,它的儿子已经遍历到一半,新加进来一个儿子to

      显然$sum[x]+=sum[to]+(sumd[x]-deep[x]*size[x])*size[to]+sumd[to]-deep[x]*size[to]$

      $sumd+=sum[to]$

      $maxi[x]=max(maxi[x],maxi[to])$

      只要注意这类方程的先后顺序即可。

      另外注意输出的先后顺序。

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<algorithm>
    #define maxn 1020020
    using namespace std;
    inline long long read(){
        long long num=0,f=1;
        char ch=getchar();
        while(!isdigit(ch)){
            if(ch=='-')    f=-1;
            ch=getchar();
        }
        while(isdigit(ch)){
            num=num*10+ch-'0';
            ch=getchar();
        }
        return num*f;
    }
    
    long long sum[maxn],maxi[maxn],mini[maxn];
    long long sumd[maxn];
    long long ansa[maxn],ansb[maxn];
    long long size[maxn];
    
    long long dfn[maxn];
    long long deep[maxn];
    long long q[maxn];
    long long stack[maxn],top;
    long long s[maxn][22];
    bool vis[maxn];
    long long ID;
    
    struct Pic{
        struct Edge{
            long long next,to;
        }edge[maxn*2];
        long long head[maxn],num;
        inline void add(long long from,long long to){
            edge[++num]=(Edge){head[from],to};
            head[from]=num;
        }
        void pre(long long x,long long fa){
            dfn[x]=++ID;    deep[x]=deep[fa]+1;
            for(long long i=head[x];i;i=edge[i].next){
                long long to=edge[i].to;
                if(to==fa)    continue;
                s[to][0]=x;
                pre(to,x);
            }
            return;
        }
        void dele(int x,int fa){
            for(int i=head[x];i;i=edge[i].next){
                int to=edge[i].to;
                if(to==fa)    continue;
                dele(to,x);
            }
            head[x]=0;
        }
        void dfs(long long x,long long fa){
            sum[x]=maxi[x]=sumd[x]=size[x]=0;    ansa[x]=0;    ansb[x]=0x7fffffff;
            mini[x]=0x7fffffff;
            //printf("%lld  %lld %lld %d>>>
    ",sum[x],x);
            for(long long i=head[x];i;i=edge[i].next){
                long long to=edge[i].to;
                if(to==fa)    continue;
                //printf("%d %d
    ",x,to);
                dfs(to,x);
                if(maxi[x])    ansa[x]=max(ansa[x],maxi[x]+maxi[to]-2*deep[x]);
                if(mini[x]!=0x7fffffff)    ansb[x]=min(ansb[x],mini[x]+mini[to]-2*deep[x]);
                maxi[x]=max(maxi[x],maxi[to]);
                mini[x]=min(mini[x],mini[to]);
                sum[x]+=sum[to];
                //printf("%lld? %d????????
    ",sum[x],x);
                if(sumd[x])    sum[x]+=(sumd[x]-deep[x]*size[x])*size[to]+(sumd[to]-deep[x]*size[to])*size[x];
                //printf("%lld %lld %d %d!!!!!!
    ",sum[x],sumd[x],x,to);
                size[x]+=size[to];
                sumd[x]+=sumd[to];
                ansa[x]=max(ansa[x],ansa[to]);
                ansb[x]=min(ansb[x],ansb[to]);
            }
            if(vis[x]){
                if(sumd[x])    sum[x]+=sumd[x]-(deep[x]*size[x]);
                sumd[x]+=deep[x];
                if(maxi[x])    ansa[x]=max(ansa[x],maxi[x]-deep[x]);
                if(mini[x]!=0x7fffffff)    ansb[x]=min(ansb[x],mini[x]-deep[x]);
                maxi[x]=max(maxi[x],deep[x]);
                mini[x]=min(mini[x],deep[x]);
                size[x]++;
            }
            //printf("%lld %d
    ",sum[x],x);
            return;
        }
    }old,vir;
    
    
    bool cmp(long long a,long long b){    return dfn[a]<dfn[b];    }
    
    inline long long LCA(long long x,long long y){
        if(deep[x]<deep[y])    swap(x,y);
        long long f=deep[x]-deep[y];
        for(long long i=0;(1<<i)<=f;++i)
            if((1<<i)&f)    x=s[x][i];
        if(x==y)    return x;
        for(long long i=21;i>=0;--i){
            if(s[x][i]==s[y][i])    continue;
            x=s[x][i];y=s[y][i];
        }
        return s[x][0];
    }
    
    int main(){
        long long n=read();
        for(long long i=1;i<n;++i){
            long long x=read(),y=read();
            old.add(x,y);    old.add(y,x);
        }
        old.pre(1,1);
        for(long long j=1;j<22;++j)
            for(long long i=1;i<=n;++i)    s[i][j]=s[s[i][j-1]][j-1];
        long long m=read();
        while(m--){
            vir.num=top=0;
            long long e=read();
            //printf("%d>>
    ",e);
            for(long long i=1;i<=e;++i){
                q[i]=read();
                vis[q[i]]=1;
            //    printf("%d>>>",dfn[q[i]]);
            }
            //printf("
    ");
            sort(q+1,q+e+1,cmp);
            for(long long i=1;i<=e;++i){
                if(top==0){
                    stack[++top]=q[i];
                    continue;
                }
                long long lca=LCA(q[i],stack[top]);
                while(dfn[lca]<dfn[stack[top]]){
                    if(dfn[lca]>=dfn[stack[top-1]]){
                        vir.add(lca,stack[top]);
                        if(stack[--top]!=lca)    stack[++top]=lca;
                        break;
                    }
                    vir.add(stack[top-1],stack[top]);
                    top--;
                }
                stack[++top]=q[i];
            }
            while(top>1){
                vir.add(stack[top-1],stack[top]);
                top--;
            }
            vir.dfs(stack[1],stack[1]);
            printf("%lld %lld %lld
    ",sum[stack[1]],ansb[stack[1]],ansa[stack[1]]);
            for(long long i=1;i<=e;++i)    vis[q[i]]=0;
            vir.dele(stack[1],stack[1]);
        }
        return 0;
    }
  • 相关阅读:
    友盟推送
    主流推送平台分析
    “完成”的定义和测试的职责
    HDU 1069 Monkey and Banana
    HDU 5587 Array
    ACM组队安排(hdu校赛)
    逆袭指数(hdu校赛)
    玩骰子(hdu校赛)
    Codeforce 546 A. Soldier and Bananas
    Codeforce 546 B. Soldier and Badges
  • 原文地址:https://www.cnblogs.com/cellular-automaton/p/8919699.html
Copyright © 2011-2022 走看看