• HEOI2014 大工程


    题目传送门

    分析:

    虚数模板练习,只是在这里放个码2333

    对于每一个询问,我们构建只与这些点有关键联系的点的新的一棵树

    由于关键点只有可能是这些点去它们的LCA

    诶每加入一个点,最多只会加入一个LCA

    所以空间是O(n)的,复杂度为O(logn)

    我们首先先预处理出每个店的dfs入栈序号和出栈序号

    首先先将读入的点加上根节点按入栈序排序

    然后求出相邻两个点的LCA

    思考一下(胡乱分析一下)我们知道这些点一定是所有关键点了

    再按入栈序排一次序

    考虑根节点到目前节点的树上关键点的路径,把它们加入一个栈中

    我们考虑新加入点与前面的栈中的点连边

    如果这个点的入栈序大于栈顶点的出栈序,那我们把栈顶pop掉

    直到符合条件即加入点在栈顶点的子树中,然后连边

    虚树就建好了。。

    然后这道题很裸,大力DP就好了

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    
    #define maxn 5000005
    #define INF 0x3f3f3f3f
    
    using namespace std;
    
    inline long long getint()
    {
        long long num=0,flag=1;char c;
        while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
        while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
        return num*flag;
    }
    
    int n,m,N;
    int fir[maxn],nxt[maxn],to[maxn],cnt;
    int fa[maxn],dpt[maxn],tp[maxn],sz[maxn],son[maxn];
    int In[maxn],Out[maxn],cur,tot;
    long long h[maxn];
    long long f[maxn],g[maxn];
    int stk[maxn],top;
    int P[maxn];
    vector<int>G[maxn];
    long long ans1,ans2,ans3;
    inline bool cmp(int x,int y){return In[x]<In[y];}
    
    inline void newnode(int u,int v)
    {to[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;}
    
    inline void dfs1(int u)
    {
        sz[u]=1;
        for(int i=fir[u];i;i=nxt[i])
            if(to[i]!=fa[u])
            {
                dpt[to[i]]=dpt[u]+1,fa[to[i]]=u;
                dfs1(to[i]);
                sz[u]+=sz[to[i]];if(sz[to[i]]>sz[son[u]])son[u]=to[i];
            }
    }
    
    inline void dfs2(int u,int ac)
    {
        In[u]=++cur,tp[u]=ac;
        if(son[u])dfs2(son[u],ac);
        for(int i=fir[u];i;i=nxt[i])if(to[i]!=fa[u]&&to[i]!=son[u])dfs2(to[i],to[i]);
        Out[u]=cur;
    }
    
    inline int LCA(int u,int v)
    {
        while(tp[u]!=tp[v])
        {
            if(dpt[tp[u]]<dpt[tp[v]])swap(u,v);
            u=fa[tp[u]];
        }
        return dpt[u]<dpt[v]?u:v;
    }
    
    inline void dp(int u)
    {
        sz[u]=P[u],f[u]=0,g[u]=P[u]?0:INF;
        for(int i=G[u].size()-1;~i;i--)
        {
            int v=G[u][i],w=dpt[v]-dpt[u];
            dp(v);
            if(sz[u]>0)ans1=max(ans1,f[u]+w+f[v]),ans2=min(ans2,g[u]+w+g[v]);
            ans3+=w*(1ll*sz[v]*(N-sz[v]));
            f[u]=max(f[u],w+f[v]);
            g[u]=min(g[u],w+g[v]);
            sz[u]+=sz[v];
        }
        P[u]=0;G[u].clear();
    }
    
    inline void solve()
    {
        int K=N=getint();top=0;
        for(int i=1;i<=K;i++)P[h[i]=getint()]=1;h[++K]=1;
        sort(h+1,h+K+1,cmp);
        for(int i=K-1;i;i--)h[++K]=LCA(h[i],h[i+1]);
        sort(h+1,h+K+1,cmp);K=unique(h+1,h+K+1)-h-1;
        stk[++top]=1;
        for(int i=2;i<=K;i++)
        {
            while(top&&Out[stk[top]]<In[h[i]])top--;
            if(top)G[stk[top]].push_back(h[i]);
            stk[++top]=h[i];
        }
        ans1=ans3=0,ans2=INF;
        dp(1);
        printf("%lld %lld %lld
    ",ans3,ans2,ans1);
        for(int i=1;i<=K;i++)sz[i]=0;
    }
    
    int main()
    {
        n=getint();
        for(int i=1;i<n;i++)
        {
            int u=getint(),v=getint();
            newnode(u,v),newnode(v,u);
        }
        dfs1(1),dfs2(1,1);memset(sz,0,sizeof sz);
        m=getint();
        while(m--)solve();
    }
    View Code

  • 相关阅读:
    【C#】.net 发送get/post请求
    【C#】什么时候使用virtual什么时候使用abstract
    【C#】为什么有可能会被多个线程修改的对象要加线程锁
    【ADO.NET】 使用通用数据库操作类Database (SQL Server)
    【ADO.NET】 基础 (SQL Server)
    【前端】模拟微信上传图片(带预览,支持预览gif)
    【前端】Html5浏览器缓存 sessionStorage 与 localStorage
    【C#】.net 导出Excel功能
    【前端】jQurey Plugin
    【c#】对象转json字符串/字符串转Json对象
  • 原文地址:https://www.cnblogs.com/Darknesses/p/12153728.html
Copyright © 2020-2023  润新知