BZOJ 1095: [ZJOI2007]Hide 捉迷藏 动态点分治+堆

写了7k多,可以说是一己之力切掉了这道毒瘤题~

开 $3$ 种堆,分别维护每个子树最大深度,以及每个节点在点分树中对父亲的贡献,和全局的最优解. 

由于需要支持堆的删除,所以写起来特别恶心+麻烦. 

细节巨多~

#include <bits/stdc++.h> 
#include <cstdio> 
#include <queue> 
#include <algorithm>  
#define N 200004 
#define setIO(s) freopen(s".in","r",stdin)  //  , freopen(s".out","w",stdout) 
using namespace std;  
int edges,n; 
int hd[N],to[N<<1],nex[N<<1];     
void add(int u,int v)
{
    nex[++edges]=hd[u],hd[u]=edges,to[edges]=v; 
}
struct Queue
{ 
    priority_queue<int>q; 
    priority_queue<int>del;   
    void re() 
    {
        while(!q.empty()&&!del.empty()&&q.top()==del.top()) q.pop(),del.pop();
    }
    void pop() 
    {
        re();                  
        if(!q.empty()) q.pop();
    } 
    void push(int x) 
    {
        re();      
        q.push(x); 
    }  
    int empty() 
    {
        re(); 
        return q.empty(); 
    }
    int size() 
    {
        re(); 
        return q.size()-del.size();    
    }   
    int top() 
    { 
        re();   
        if(!q.empty()) 
            return q.top(); 
        else 
            return -1; 
    }   
    void erase(int x)
    {
        re();
        del.push(x);
    }   
}F[N],G[N],Total; 
namespace tree
{  
    int dep[N],size[N],son[N],top[N],fa[N]; 
    void dfs1(int u,int ff)
    {
        fa[u]=ff,dep[u]=dep[ff]+1,size[u]=1; 
        for(int i=hd[u];i;i=nex[i]) 
            if(to[i]!=ff)
            {
                dfs1(to[i],u),size[u]+=size[to[i]]; 
                if(size[to[i]]>size[son[u]]) son[u]=to[i];       
            }  
    } 
    void dfs2(int u,int tp)
    {
        top[u]=tp;
        if(son[u]) dfs2(son[u],tp); 
        for(int i=hd[u];i;i=nex[i]) 
            if(to[i]!=fa[u]&&to[i]!=son[u]) 
                dfs2(to[i],to[i]); 
    } 
    int LCA(int x,int y)
    {
        while(top[x]!=top[y]) 
            dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]]; 
        return dep[x]<dep[y]?x:y; 
    } 
    int Dis(int x,int y)
    {
        return dep[x]+dep[y]-(dep[LCA(x,y)]<<1);
    }
};  
int root,sn;
int mx[N],vis[N],Fa[N],size[N],sta[N]; 
void dfs(int u,int ff)
{
    size[u]=1; 
    for(int i=hd[u];i;i=nex[i]) 
        if(to[i]!=ff&&!vis[to[i]]) 
            dfs(to[i],u),size[u]+=size[to[i]]; 
}
void getroot(int u,int ff)
{   
    size[u]=1,mx[u]=0; 
    for(int i=hd[u];i;i=nex[i]) 
        if(!vis[to[i]]&&to[i]!=ff) 
            getroot(to[i],u),mx[u]=max(mx[u],size[to[i]]),size[u]+=size[to[i]]; 
    mx[u]=max(mx[u],sn-size[u]);  
    if(mx[u]<mx[root]) root=u; 
}   
void work(int u,int ff,int rt)
{ 
    if(Fa[rt]) 
        G[rt].push(tree::Dis(Fa[rt],u));    
    for(int i=hd[u];i;i=nex[i]) 
        if(to[i]!=ff&&!vis[to[i]]) 
            work(to[i],u,rt);        
}  
void calc(int u) 
{   
    work(u,0,u);    
    F[u].push(0);     
    if(Fa[u]&&G[u].size()) F[Fa[u]].push(G[u].top());            
}
void prepare(int u) 
{  
    vis[u]=1; 
    calc(u);       
    for(int i=hd[u];i;i=nex[i]) 
        if(!vis[to[i]]) 
            dfs(to[i],u),sn=size[to[i]],root=0,getroot(to[i],u),Fa[root]=u,prepare(root);       
    if(F[u].size()>=2) 
    {
        int a=0,b=0; 
        a=F[u].top(), F[u].pop();    
        b=F[u].top(), F[u].pop();               
        Total.push(a+b);          
        F[u].push(a), F[u].push(b);    
    }      
} 
// 开灯 (更小)                         
void open(int u,int key) 
{ 
    int a=0,b=0,a1=0,b1=0; 
    if(F[u].size()>=2) 
    {
        a=F[u].top(),F[u].pop();     
        b=F[u].top(),F[u].pop();     
        F[u].push(a),F[u].push(b),F[u].erase(key);        
        if(F[u].size()>=2) 
        { 
            a1=F[u].top(),F[u].pop(); 
            b1=F[u].top(),F[u].pop();      
            F[u].push(a1),F[u].push(b1);     
            if(a1+b1!=a+b) 
            {
                Total.erase(a+b); 
                Total.push(a1+b1);    
            } 
        }
        else Total.erase(a+b); 
    }
    else F[u].erase(key); 
} 
void shut(int u,int key)
{ 
    int a=0,b=0,a1=0,b1=0; 
    if(F[u].size()>=1) 
    { 
        if(F[u].size()>=2) 
        { 
            a=F[u].top(),F[u].pop(); 
            b=F[u].top(),F[u].pop();     
            F[u].push(a),F[u].push(b),F[u].push(key);                       
            a1=F[u].top(),F[u].pop(); 
            b1=F[u].top(),F[u].pop();    
            F[u].push(a1),F[u].push(b1);        
            if(a1+b1!=a+b) 
            {
                Total.erase(a+b);        
                Total.push(a1+b1);    
            }
        } 
        else 
        {
            a=F[u].top(),F[u].push(key);    
            Total.push(a+key);    
        }
    }
    else F[u].push(key);          
}
// 开灯(更小)
void update1(int u) 
{   
    open(u,0);           
    for(int U=u;Fa[u];u=Fa[u]) 
    {     
        int dis=tree::Dis(U,Fa[u]); 
        if(G[u].top()==dis) 
        { 
            G[u].erase(dis);  
            open(Fa[u],dis);             
            if(!G[u].empty()) 
            { 
                int a=G[u].top();
                shut(Fa[u],a);  
            }
        }
        else G[u].erase(dis);         
    }
}
// 关灯(更大)
void update2(int u) 
{ 
    shut(u,0);   
    for(int U=u;Fa[u];u=Fa[u]) 
    {
        int dis=tree::Dis(U,Fa[u]); 
        if(G[u].top()>=dis) G[u].push(dis);                      
        else if(G[u].empty()) 
        {
            G[u].push(dis); 
            shut(Fa[u],dis); 
        }
        else
        { 
            shut(Fa[u],dis);     
            open(Fa[u],G[u].top());         
            G[u].push(dis); 
        } 
    }
} 
int main()     
{ 
    int i,j,Q; 
    // setIO("input"); 
    scanf("%d",&n);  
    for(i=1;i<n;++i) 
    {
        int a,b; 
        scanf("%d%d",&a,&b),add(a,b),add(b,a); 
    } 
    tree::dfs1(1,0),tree::dfs2(1,1);      
    mx[0]=sn=n,root=0,getroot(1,0),prepare(root);      
    scanf("%d",&Q); 
    for(i=1;i<=Q;++i)        
    {
        char str[2]; 
        scanf("%s",str); 
        if(str[0]=='C') 
        {  
            int u; 
            scanf("%d",&u); 
            if(sta[u]==0) 
            {
                update1(u); 
            }
            else 
            {
                update2(u);     
            }
            sta[u]^=1;     
        }
        if(str[0]=='G') 
        { 
            if(Total.empty()) 
                printf("-1\n");                  
            else 
                printf("%d\n",Total.top());     
        }
    } 
}

  

posted @ 2019-09-03 18:36  EM-LGH  阅读(163)  评论(0编辑  收藏  举报