zoukankan      html  css  js  c++  java
  • 【BZOJ5329】战略游戏(SDOI2018)-圆方树+虚树

    测试地址:战略游戏
    做法:本题需要用到圆方树+虚树。
    显而易见的是,两个点之间路径的必经点,就等于它们之间路径上的所有割点。因此我们很快想到建出圆方树,这样两点间路径上所有的圆点(除去两端)就是对应的割点。而询问一个集合,问能切开集合中某两个点的所有点,那就是求所有这些点两两之间路径的并,答案就等于并集中圆点的数目减去询问集合的大小(因为询问集合内的点不能算作答案)。
    树上一个点集两两之间路径的并也是一棵树,用更加熟悉的一个词来说,是一棵虚树,因此我们在圆方树上求虚树即可,时间复杂度为O(|S|log|S|)
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int N=200010;
    int T,n,m,q;
    int first[N],firstt[N],tot,totpbc;
    int low[N],dfn[N],st[N],top,tim,pos[N],p[N<<1],s;
    int fa[N][20],dep[N],dis[N];
    bool vis[N];
    struct edge
    {
        int v,next;
    }e[N<<1],t[N<<1];
    
    void insert(int a,int b)
    {
        e[++tot].v=b;
        e[tot].next=first[a];
        first[a]=tot;
    }
    
    void insertt(int a,int b)
    {
        t[++tot].v=b;
        t[tot].next=firstt[a];
        firstt[a]=tot;
    }
    
    void tarjan(int v,int fa)
    {
        low[v]=dfn[v]=++tim;
        st[++top]=v;
        vis[v]=1;
        for(int i=first[v];i;i=e[i].next)
            if (e[i].v!=fa)
            {
                if (!vis[e[i].v])
                {
                    tarjan(e[i].v,v);
                    low[v]=min(low[v],low[e[i].v]);
                    if (low[e[i].v]>=dfn[v])
                    {
                        ++totpbc;
                        insertt(v,totpbc);
                        do
                        {
                            insertt(totpbc,st[top]);
                        }while(st[top--]!=e[i].v);
                    }
                }
                else low[v]=min(low[v],dfn[e[i].v]);
            }
    }
    
    void dfs(int v)
    {
        pos[v]=++tim;
        for(int i=firstt[v];i;i=t[i].next)
        {
            fa[t[i].v][0]=v;
            dep[t[i].v]=dep[v]+1;
            dis[t[i].v]=dis[v]+(t[i].v<=n);
            dfs(t[i].v);
        }
    }
    
    bool cmp(int a,int b)
    {
        return pos[a]<pos[b];
    }
    
    int lca(int x,int y)
    {
        if (dep[x]<dep[y]) swap(x,y);
        for(int i=18;i>=0;i--)
            if (dep[fa[x][i]]>=dep[y]) x=fa[x][i];
        if (x==y) return x;
        for(int i=18;i>=0;i--)
            if (fa[x][i]!=fa[y][i])
                x=fa[x][i],y=fa[y][i];
        return fa[x][0];
    }
    
    void build()
    {
        sort(p+1,p+s+1,cmp);
        for(int i=1;i<s;i++)
            p[s+i]=lca(p[i],p[i+1]);
        sort(p+1,p+(s<<1),cmp);
    
        int tot=1;
        for(int i=1;i<(s<<1)-1;i++)
            if (p[i]!=p[i+1]) p[++tot]=p[i+1];
    
        int ans;
        top=ans=0;
        for(int i=1;i<=tot;i++)
        {
            while(top&&lca(st[top],p[i])!=st[top]) top--;
            st[++top]=p[i];
            if (top>1) ans+=dis[st[top]]-dis[st[top-1]];
        }
        if (p[1]<=n) ans++;
        printf("%d
    ",ans-s);
    }
    
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            memset(first,0,sizeof(first));
            memset(firstt,0,sizeof(firstt));
            tot=0;
    
            scanf("%d%d",&n,&m);
            for(int i=1;i<=m;i++)
            {
                int a,b;
                scanf("%d%d",&a,&b);
                insert(a,b),insert(b,a);
            }
    
            tot=top=tim=0,totpbc=n;
            memset(vis,0,sizeof(vis));
            tarjan(1,0);
    
            memset(fa,0,sizeof(fa));
            tim=0;
            dis[1]=1,dep[1]=0,dep[0]=-1;
            dfs(1);
            for(int i=1;i<=18;i++)
                for(int j=1;j<=totpbc;j++)
                    fa[j][i]=fa[fa[j][i-1]][i-1];
    
            scanf("%d",&q);
            for(int i=1;i<=q;i++)
            {
                scanf("%d",&s);
                for(int j=1;j<=s;j++)
                    scanf("%d",&p[j]);
                build();
            }
        }
    
        return 0;
    }
  • 相关阅读:
    容器技术(三)搭建本地 Registry【15】
    容器技术(三) 使用公共 Registry【14】
    容器技术(三) 镜像命名的最佳实践【13】
    容器技术(三) RUN vs CMD vs ENTRYPOINT【12】
    容器技术(三) dockerfile常用指令【11】
    容器技术(三) dockerfile调试【10】
    容器技术(三) 镜像缓存特性【9】
    容器技术(三) Dockerfile 构建镜像【8】
    容器技术(三)构建镜像【7】
    layui的图标知识
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793321.html
Copyright © 2011-2022 走看看