• 【BZOJ1095】捉迷藏(ZJOI2007)-动态点分治+堆


    测试地址:捉迷藏
    做法:本题需要用到动态点分治+堆。
    一棵树上有黑点和白点,求两个黑点之间的最远距离,如果没有修改,我们完全可以使用DP或者点分治的方法求出。现在的问题是带了修改,那么从DP的角度来考虑就比较难了,所以我们从点分治的角度考虑怎么拓展。
    回顾点分治的思路,我们对一棵树找到它的重心,然后递归处理删去这个点后该树分成的所有子树。对于每一棵树,考虑过重心的所有路径,用类似DP的方法可以求出这棵树内过重心的最远距离黑点对。考虑这样一种暴力,每次修改都暴力做一次点分治,这样显然会增大时间复杂度。但考虑到,每次修改只涉及到一个点,也就是说只涉及到一端为这个点的所有路径,我们发现它最多会影响logn个点上求出的最远点对。至于为什么,请继续往下看。
    考虑构造这样一个结构来描述点分治的过程:对于一棵树,先将它的重心作为根,递归处理它的所有子树,并从重心向这些子树的重心分别连边。显然这样连出来的也是一棵树,这棵树的深度最多为logn。我们把这棵树称为点分树,它是一个描述点分治过程的结构。
    我们发现,修改一个点,影响到的点就是它在点分树上的所有祖先,也就是最多影响到logn个。回顾原先的点分治需要维护什么东西:对于一棵点分树上的子树,维护子树内所有黑点到根的祖先的最远距离;对于点分树上的每一个点,维护几棵子树中最远黑点距离的最大值和次大值;当然,还要维护对于所有的点,求出的最远黑点点对的距离。我们发现这些都是要维护某些值中最大的几个值,用堆来维护即可,至于可定值删除堆的写法详见本人的代码。那么我们每修改一个点,都暴力修改它在点分树上所有祖先的信息,每次修改一个祖先的信息都是O(logn)的,于是我们就得到了一个时间复杂度为O(mlog2n),空间复杂度为O(mlogn)的做法,可以通过此题。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    int n,m,first[100010]={0},firstt[100010]={0},tot=0,dep[100010]={0},fa[100010];
    int f[100010],mxson[100010],siz[100010],q[100010],totsiz,top;
    int dis[100010][20],totvis;
    bool vis[100010]={0};
    struct edge
    {
        int v,next;
    }e[200010],t[100010];
    struct heap
    {
        priority_queue<int> a,b;
        void push(int x) {if (x>=0) a.push(x);}
        void del(int x) {if (x>=0) b.push(x);}
        int size() {return a.size()-b.size();}
        int top()
        {
            if (!size()) return -1;
            while(!b.empty()&&a.top()==b.top()) a.pop(),b.pop();
            return a.top();
        }
        int sum()
        {
            if (size()<2) return -1;
            int A=top();a.pop();
            int B=top();push(A);
            return A+B;
        }
    }p[100010],st[100010],ans;
    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 dp(int v,int fa)
    {
        totsiz++;
        q[++top]=v;
        mxson[v]=0;
        siz[v]=1;
        for(int i=first[v];i;i=e[i].next)
            if (e[i].v!=fa&&!vis[e[i].v])
            {
                dp(e[i].v,v);
                mxson[v]=max(mxson[v],siz[e[i].v]);
                siz[v]+=siz[e[i].v];
            }
    }
    
    int find(int v)
    {
        totsiz=top=0;
        dp(v,0);
        int ans=100000000,ansi;
        for(int i=1;i<=top;i++)
            if (max(mxson[q[i]],totsiz-siz[q[i]])<ans)
            {
                ans=max(mxson[q[i]],totsiz-siz[q[i]]);
                ansi=q[i];
            }
        return ansi;
    }
    
    void put(int v,int tar,int d,int Fa)
    {
        dis[v][dep[v]-dep[tar]]=d;
        p[tar].push(d);
        for(int i=first[v];i;i=e[i].next)
            if (e[i].v!=Fa&&!vis[e[i].v]) put(e[i].v,tar,d+1,v);
    }
    
    int solve(int v,int Fa)
    {
        v=find(v);
        vis[v]=1;
        dep[v]=dep[Fa]+1;
        fa[v]=Fa;
        for(int i=first[v];i;i=e[i].next)
            if (!vis[e[i].v])
            {
                int nx=solve(e[i].v,v);
                insertt(v,nx);
                put(e[i].v,nx,1,0);
            }
    
        st[v].push(0);
        for(int i=firstt[v];i;i=t[i].next)
            st[v].push(p[t[i].v].top());
        ans.push(st[v].sum());
    
        vis[v]=0;
        return v;
    }
    
    void turn(int v)
    {
        vis[v]=!vis[v];
        if (vis[v])
        {
            totvis--;
            ans.del(st[v].sum());
            st[v].del(0);
            ans.push(st[v].sum());
        }
        else
        {
            totvis++;
            ans.del(st[v].sum());
            st[v].push(0);
            ans.push(st[v].sum());
        }
    
        int h=0,x=v;
        while(x)
        {
            if (fa[x])
            {
                ans.del(st[fa[x]].sum());
                st[fa[x]].del(p[x].top());
            }
            if (vis[v]) p[x].del(dis[v][h]);
            else p[x].push(dis[v][h]);
            if (fa[x])
            {
                st[fa[x]].push(p[x].top());
                ans.push(st[fa[x]].sum());
            }
            h++;
            x=fa[x];
        }
    }
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<n;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            insert(a,b),insert(b,a);
        }
    
        tot=0;
        solve(1,0);
        totvis=n;
    
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            char op[3];
            scanf("%s",op);
            if (op[0]=='G')
            {
                if (totvis>=2) printf("%d
    ",ans.top());
                else printf("%d
    ",totvis?0:-1);
            }
            else
            {
                int x;
                scanf("%d",&x);
                turn(x);
            }
        }
    
        return 0;
    }
  • 相关阅读:
    (bfs入门)宝岛探险
    (bfs入门)走迷宫
    环形的处理P1880 [NOI1995]石子合并
    ZOJ2227Minimax三角划分
    UVA11400 Lighting System Design
    字符串匹配入门
    UVA12563 Jin Ge Jin Qu hao
    HDU1619 Unidirectional TSP
    ZOJ2581Tour
    UVA1025 A Spy in the Metro
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793371.html
Copyright © 2020-2023  润新知