码迷,mamicode.com
首页 > 其他好文 > 详细

HNOI2014 世界树

时间:2015-04-23 21:31:54      阅读:202      评论:0      收藏:0      [点我收藏+]

标签:

Description

技术分享
 

Input

技术分享

Output

技术分享
 

Sample Input

10

2 1

3 2

4 3

5 4

6 1

7 3

8 3

9 4

10 1

5

2

6 1

5

2 7 3 6 9

1

8

4

8 7 10 3

5

2 9 3 5 8

Sample Output

1 9

3 1 4 1 1

10

1 1 3 5

4 1 3 1 1
 

Data Constraint

技术分享
 

Hint

技术分享

技术分享
 
我们每次询问的关键点个数是有限的,实树上很多节点的情况实际是一样的,我们可以直接一起处理。
那么我们要构建一个叫虚树的东西。只把和这几个点有关系的点建入树中,没有在虚树中的点直接用size统计答案即可
虚树中要放入关键点以及dfs序相序关键点的lca。构建虚树的方法:用单调栈维护树的最右链,每加入一个点,把之前非父亲的点弹出,然后和父亲连边即可
 
然后我们在虚树上跑最短路,找出离每个点最近的点,
接着对于虚树的每一条边,
1.如果两端点的最近点相同,那么这条边上的最近点均相同,直接计入答案即可
2.不同,则在边上找一个分界点,然后用1的情况处理即可
 
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;

struct dd{
    int dis,x;
    bool operator < (dd a) const
    {
        return dis>a.dis;
    }
    dd(int a=0,int b=0){
        dis=a;
        x=b;
    }
};

priority_queue<dd> H;

int num[300011],a[300011],ys[300011],stk[300011],ans[300011];
int t,T,tc,ts,tot,tt,top,n,m,i,j,x,z,root;
int dfn[300011],next[600011],y[600011],g[300011],dep[300011];
int G[300011],Next[600011],Y[600011],len[600011];
int fa[300011][19],d[300011],near[300011],rank[300011],size[300011];
bool vis[300011];


bool cmp(int a,int b)
{
    return dfn[a]<dfn[b];
}

void star(int i,int j)
{
    tt++;
    next[tt]=g[i];
    g[i]=tt;
    y[tt]=j;
}

void stt(int i,int j,int k)
{
    tc++;
    Next[tc]=G[i];
    G[i]=tc;
    Y[tc]=j;
    len[tc]=k;
}

void dfs(int x)
{
    int j,k;
    dfn[x]=++tot;
    size[x]=1;
    j=g[x];
    while(j!=0){
        k=y[j];
        if(k!=fa[x][0]){
            fa[k][0]=x;
            dep[k]=dep[x]+1;
            dfs(k);
            size[x]+=size[k];
        }
        j=next[j];
    }
}

int get(int x,int z)
{
    int i,l,e;
    if(dep[x]<dep[z])swap(x,z);
    l=dep[x]-dep[z];
    e=0;
    while(l){
        if(l%2==1)x=fa[x][e];
        e++;
        l/=2;
    }
    if(x==z)return x;
    for(i=18;i>=0;i--)if(fa[x][i]!=fa[z][i]){
        x=fa[x][i];
        z=fa[z][i];
    }
    return fa[x][0];
}

void Buildtree()
{
    int i;
    sort(num+1,num+1+t,cmp);
    T=t;
    for(i=1;i<t;i++)num[++T]=get(num[i],num[i+1]);
    sort(num+1,num+1+T,cmp);
    ts=0;
    for(i=1;i<=T;i++)if(num[i]!=num[i-1]){
        ts++;
        a[ts]=num[i];
    }
    memset(G,0,sizeof(G));
    tc=0;
    top=0;
    root=0;
    for(i=1;i<=ts;i++){
        while(top&&!(dfn[a[i]]>=dfn[stk[top]]&&dfn[a[i]]<dfn[stk[top]]+size[stk[top]]))top--;
        if(top){
            stt(stk[top],a[i],dep[a[i]]-dep[stk[top]]);
            stt(a[i],stk[top],dep[a[i]]-dep[stk[top]]);
        }
        stk[++top]=a[i];
        if(root==0||dep[a[i]]<dep[root])root=a[i];
    }
}

void Dij()
{
    dd tp;
    int j,k,i;
    while(!H.empty())H.pop();
    memset(near,0,sizeof(near));
    memset(d,127,sizeof(d));
    memset(vis,false,sizeof(vis));
    for(i=1;i<=t;i++){
        d[ys[i]]=0;
        near[ys[i]]=ys[i];
        vis[ys[i]]=true;
        H.push(dd(0,ys[i]));
    }
    while(!H.empty()){
        tp=H.top();
        H.pop();
        j=G[tp.x];
        while(j!=0){
            k=Y[j];
            if(d[tp.x]+len[j]<d[k]||(d[tp.x]+len[j]==d[k]&&near[tp.x]<near[k])){
                d[k]=d[tp.x]+len[j];
                near[k]=near[tp.x];
                if(!vis[k]){
                    vis[k]=true;
                    H.push(dd(d[k],k));
                }
            }
            j=Next[j];
        }
        vis[tp.x]=false;
    }
}

int jump(int x,int z)
{
    int e;
    e=0;
    while(z){
        if(z%2==1)x=fa[x][e];
        z/=2;
        e++;
    }
    return x;
}

bool check(int x,int z,int ds)
{
    int dz,dx,dt;
    dt=jump(x,ds);
    dx=d[x]+dep[x]-dep[dt];
    dz=d[z]+dep[dt]-dep[z];
    if(dx<dz||(dx==dz&&near[x]<near[z]))return true;
    else return false;
}

int ef(int x,int z,int l,int r)
{
    int mid;
    while(l<=r){
        mid=(l+r)/2;
        if(check(x,z,mid))l=mid+1;
        else r=mid-1;
    }
    return jump(x,r);
}

void Tfind(int x,int z)
{
    int nk,fj;
    nk=jump(x,dep[x]-dep[z]-1);
    if(near[x]==near[z]){
        ans[rank[near[x]]]+=size[nk]-size[x];
    }
    else{
        if(dep[x]-dep[z]-1>0){
            fj=ef(x,z,1,dep[x]-dep[z]-1);
            ans[rank[near[x]]]+=size[fj]-size[x];
            ans[rank[near[z]]]+=size[nk]-size[fj];
        }
    }
}

void find(int x,int faf)
{
    int ad,j,k,nk;
    if(x==root)ans[rank[near[x]]]+=n-size[x];
    j=G[x];
    ad=size[x];
    while(j!=0){
        k=Y[j];
        if(k!=faf){
            nk=jump(k,dep[k]-dep[x]-1);
            Tfind(k,x);
            find(k,x);
            ad-=size[nk];
        }
        j=Next[j];
    }
    ans[rank[near[x]]]+=ad;
}

int main()
{
    scanf("%d",&n);
    for(i=1;i<n;i++){
        scanf("%d%d",&x,&z);
        star(x,z);
        star(z,x);
    }
    dfs(1);
    for(i=1;i<=18;i++)
        for(j=1;j<=n;j++)fa[j][i]=fa[fa[j][i-1]][i-1];
    scanf("%d",&m);
    for(i=1;i<=m;i++){
        scanf("%d",&t);
        for(j=1;j<=t;j++){
            scanf("%d",&num[j]);
            rank[num[j]]=j;
            ys[j]=num[j];
            ans[j]=0;
        }
        ts=0;
        Buildtree();
        Dij();
        find(root,0);
        for(j=1;j<=t;j++)printf("%d ",ans[j]);
        printf("\n");
    }
}

 

HNOI2014 世界树

标签:

原文地址:http://www.cnblogs.com/applejxt/p/4451648.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!