BZOJ 5329: [Sdoi2018]战略游戏 (圆方树,树链的并)

一定注意,这里不要写错:  

$low[y]>=dfn[x]$,开始的时候把 $dfn[x]$ 写成 $low[x]$ 调了一下午......    

然后根据圆方树优美的性质,我们发现题中要求的就是圆方树上一些点构成的树链的并中圆点个数.   

这个问题可以用虚树或树链的并解决.  

code:   

#include <cstdio> 
#include <cstring> 
#include <algorithm>   
#include <vector>     
#define N 200006   
#define setIO(s) freopen(s".in","r",stdin)  , freopen(s".out","w",stdout) 
using namespace std;       
vector<int>G[N];  
int edges,tim,fr,tot,n,m,Q;                
int hd[N<<1],to[N<<1],nex[N<<1],dfn[N],low[N],S[N];   
int dn[N],dep[N],size[N],son[N],top[N],fa[N],depth[N];    
int arr[N];      
bool cmp(int a,int b) 
{
    return dn[a]<dn[b];  
}
void add(int u,int v) 
{
    nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;  
} 
void tarjan(int x) 
{
    dfn[x]=low[x]=++tim;      
    S[++fr]=x;     
    for(int i=hd[x];i;i=nex[i]) 
    {
        int y=to[i];     
        if(!dfn[y]) 
        {
            tarjan(y);   
            low[x]=min(low[x],low[y]);    
            if(low[y]>=dfn[x]) 
            {
                ++tot;         
                G[x].push_back(tot); 
                G[tot].push_back(x);  
                for(int p=0;p!=y;--fr) 
                {
                    p=S[fr];        
                    G[tot].push_back(p); 
                    G[p].push_back(tot);      
                }               
            }
        }   
        else {
            low[x]=min(low[x],dfn[y]);               
        }
    }    
}     
void dfs1(int x,int ff) 
{     
    dn[x]=++tim,depth[x]=depth[ff]+1;    
    fa[x]=ff,size[x]=1,dep[x]=dep[ff]+(x<=n);       
    for(int i=0;i<G[x].size();++i) 
    {
        int y=G[x][i];   
        if(y==ff) continue;           
        dfs1(y,x);   
        if(size[y]>size[son[x]])  
            son[x]=y;   
        size[x]+=size[y];  
    }
}
void dfs2(int x,int tp) 
{
    top[x]=tp;        
    if(son[x])   
        dfs2(son[x],tp);   
    for(int i=0;i<G[x].size();++i) 
    {
        if(G[x][i]!=fa[x]&&G[x][i]!=son[x])  
            dfs2(G[x][i],G[x][i]); 
    }
}   
int get_lca(int x,int y) 
{
    while(top[x]!=top[y]) 
    {  
        depth[top[x]]>depth[top[y]]?x=fa[top[x]]:y=fa[top[y]];  
    } 
    return depth[x]<depth[y]?x:y;   
}         
void calc() 
{
    int num,lca; 
    scanf("%d",&num);    
    for(int i=1;i<=num;++i)
        scanf("%d",&arr[i]);          
    sort(arr+1,arr+1+num,cmp);        
    for(int i=1;i<=num;++i) 
    { 
        if(i==1) lca=arr[1];  
        else lca=get_lca(lca,arr[i]);
    } 
    int ans=0;    
    for(int i=1;i<=num;++i) 
        ans+=dep[arr[i]]-dep[fa[lca]];   
    for(int i=2;i<=num;++i) 
    {
        int p=get_lca(arr[i],arr[i-1]);    
        ans-=(dep[p]-dep[fa[lca]]);       
    }                
    printf("%d\n",ans-num);    
}
void solve() 
{
    scanf("%d%d",&n,&m);   
    for(int i=1;i<=m;++i) 
    {
        int x,y;   
        scanf("%d%d",&x,&y);              
        add(x,y),add(y,x); 
    }        
    tot=n;
    tarjan(1);     
    tim=0;    
    dfs1(1,0); 
    dfs2(1,1);           
    scanf("%d",&Q);       
    for(int i=1;i<=Q;++i) calc();    
    for(int i=0;i<=2*n;++i)  
    {
        G[i].clear();    
        low[i]=dfn[i]=son[i]=dep[i]=depth[i]=fa[i]=0;    
    }
    for(int i=0;i<=edges;++i) 
        nex[i]=to[i]=0;     
    for(int i=0;i<=n;++i) 
        hd[i]=0;        
    edges=tim=fr=tot=0; 

}
int main() 
{ 
    // setIO("input"); 
    int T;  
    scanf("%d",&T);   
    while(T--) solve();  
    return 0; 
}

  

猜你喜欢

转载自www.cnblogs.com/guangheli/p/12589063.html