• HNOI2014 世界树


    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("
    ");
        }
    }
  • 相关阅读:
    OpenGL I420渲染(四)
    iftop查看带宽占用情况
    mysql join语句原理
    mysql查询sql及索引优化
    MySQL之索引
    IO概念和五种IO模型
    Ubuntu 14.10 下Hive配置
    Hadoop 管理工具HUE配置初始配置
    Ubuntu 15.10 下Scala 操作Redis Cluster
    Hadoop 管理工具HUE配置HBase配置
  • 原文地址:https://www.cnblogs.com/applejxt/p/4451648.html
Copyright © 2020-2023  润新知