bzoj3572: [Hnoi2014]世界树

首先先套路上虚树

对于虚树,分成两类点:一种是作为议事处的,一种是虚树加的lca

如果树上没有加的点,对于两个议事处之间的路径,一半归下面,一半归上面,这个就很好解决了

对于lca,我们需要找到在树上离它最近的议事处,此时lca相当于帮这个议事处去和其他的点分配路径上的点

这个我们用二次扫描+换根法就可以弄出来

说得轻巧码量巨大

叫我AK·再做数据结构我是狗·C·真香·qhzdy

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;

struct node
{
    int x,y,next;
}a[610000];int len,last[310000];
void ins(int x,int y)
{
    len++;
    a[len].x=x;a[len].y=y;
    a[len].next=last[x];last[x]=len;
}
int z,ys[310000];
int Bin[30],f[30][310000],dep[310000],tot[310000];
void dfs(int x)
{
    ys[x]=++z; tot[x]=1;
    for(int i=1;Bin[i]<=dep[x];i++)f[i][x]=f[i-1][f[i-1][x]];
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(y!=f[0][x])
        {
            f[0][y]=x;
            dep[y]=dep[x]+1;
            dfs(y);
            tot[x]+=tot[y];
        }
    }
}
int LCA(int x,int y)
{
    if(dep[x]<dep[y])swap(x,y);
    for(int i=25;i>=0;i--)
        if(dep[x]-dep[y]>=Bin[i])x=f[i][x];
    if(x==y)return x;
    
    for(int i=25;i>=0;i--)
        if(dep[x]>=Bin[i]&&f[i][x]!=f[i][y])x=f[i][x],y=f[i][y];
    return f[0][x];
}
int findkth(int x,int k)
{
    for(int i=25;i>=0;i--)
        if(k>=Bin[i])x=f[i][x],k-=Bin[i];
    return x;
}

//---------------------------------------init-----------------------------------------------------------

int c[310000];

int h[310000],h2[310000];
bool cmp(int h1,int h2){return ys[h1]<ys[h2];}

node e[610000];int elen,elast[310000];
void eins(int x,int y)
{
    elen++;
    e[elen].x=x;e[elen].y=y;
    e[elen].next=elast[x];elast[x]=elen;
}
///~~~~~~~~~~~~边目录~~~~~~~~~~~~~~~~~~

int top,sta[310000];bool islca[310000];
void VirtualTree(int m)
{
    sort(h+1,h+m+1,cmp);
    
    top=0;sta[++top]=1;
    for(int i=1;i<=m;i++)
    {
        int lca=LCA(h[i],sta[top]);
        while(1)
        {
            if(dep[lca]>=dep[sta[top-1]]&&lca!=sta[top-1]&&lca!=sta[top])
            {
                eins(lca,sta[top]);top--;
                sta[++top]=lca;
                break;
            }
            if(lca==sta[top])break;
            bool bk=(lca==sta[top-1]);
            if(top>1)
                eins(sta[top-1],sta[top]),top--;
            if(bk)break;
        }
        if(h[i]!=sta[top])sta[++top]=h[i];
        islca[h[i]]=false;
    }
    while(top>1)
        eins(sta[top-1],sta[top]),top--;
}

//--------------------------------------composition-----------------------------------------------------------

int p[2][310000],dis[2][310000],hp[310000],hd[310000];

int d1,d2;
bool check(int x,int y,int w)
{
    if(y==-1)return false;
    if(p[w][x]==-1)return true;
    return d1==d2?p[w][x]>y:d1>d2;
}
//~~~~~~~~~~~烦人的check~~~~~~~~~~~~~

void solvert(int x,int fr)
{
    p[0][x]=p[1][x]=-1;
    if(!islca[x])p[0][x]=x,dis[0][x]=0;
    for(int k=elast[x];k;k=e[k].next)
    {
        int y=e[k].y;
        if(y!=fr)
        {
            solvert(y,x);
            
            bool bk=false;
            d1=dis[0][x],d2=dis[0][y]+dep[y]-dep[x];
            if(check(x,p[0][y],0))
            {
                bk=true;
                p[0][x]=p[0][y], dis[0][x]=d2;
                
                d1=dis[1][x],d2=dis[1][y]+dep[y]-dep[x];
                if(check(x,p[1][y],1))
                    p[1][x]=p[1][y], dis[1][x]=d2;
            }
            d1=dis[1][x],d2=dis[0][y]+dep[y]-dep[x];
            if(!bk&&check(x,p[0][y],1))
                p[1][x]=p[0][y], dis[1][x]=d2;
        }
    }
}
void changert(int x,int fr)
{
    hp[x]=p[0][x],hd[x]=dis[0][x];
    for(int k=elast[x];k;k=e[k].next)
    {
        int y=e[k].y;
        if(y!=fr)
        {
            if(p[0][x]==p[0][y])
            {
                d1=dis[0][y],d2=dis[1][x]+dep[y]-dep[x];
                if(check(y,p[1][x],0))
                    p[0][y]=p[1][x], dis[0][y]=d2;
            }
            else 
            {
                d1=dis[0][y],d2=dis[0][x]+dep[y]-dep[x];
                if(check(y,p[0][x],0))
                    p[0][y]=p[0][x], dis[0][y]=d2;
            }
            changert(y,x);
        }
    }
}

//--------------------------------------换根inithp-----------------------------------------------------------

void calc(int x,int y)
{
    if(hp[x]==hp[y])
    {
        int yy=findkth(y,dep[y]-dep[x]-1);
        c[hp[x]]+=tot[yy]-tot[y];
    }
    else
    {
        int pt=dep[y]-dep[x]-1+hd[x]+hd[y];        
        int xx=findkth(y,dep[y]-dep[x]-1);
        int yy=findkth(y,pt/2+((pt%2==1)?(hp[y]<hp[x]):0)-hd[y]);
            
        c[hp[x]]+=tot[xx]-tot[yy];
        c[hp[y]]+=tot[yy]-tot[y];
    }
}
void solve(int x,int fr)
{
    c[hp[x]]+=tot[x];
    for(int k=elast[x];k;k=e[k].next)
    {
        int y=e[k].y;
        if(y!=fr)
        {
            c[hp[x]]-=tot[findkth(y,dep[y]-dep[x]-1)];
            calc(x,y);
            solve(y,x);
        }
    }
    elast[x]=0;
    islca[x]=true;
    hp[x]=hd[x]=-1;
}

//---------------------------------------------solve---------------------------------------------------------

int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    int n,x,y;
    scanf("%d",&n);
    len=0;memset(last,0,sizeof(last));
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        ins(x,y),ins(y,x);
    }
    Bin[0]=1;for(int i=1;i<=25;i++)Bin[i]=Bin[i-1]*2;
    dep[1]=0;dfs(1);
    
    int Q,m;
    scanf("%d",&Q);
    memset(hp,-1,sizeof(hp));
    memset(islca,true,sizeof(islca));
    while(Q--)
    {
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
            scanf("%d",&h[i]),h2[i]=h[i];
        VirtualTree(m);
        
        solvert(1,0);
        changert(1,0);
        
        solve(1,0);elen=0;
        for(int i=1;i<m;i++)printf("%d ",c[h2[i]]),c[h2[i]]=0;
        printf("%d\n",c[h2[m]]),c[h2[m]]=0;
 }
    return 0;
}

 

posted @ 2019-01-02 09:40  AKCqhzdy  阅读(149)  评论(0编辑  收藏  举报