zoukankan      html  css  js  c++  java
  • 1759:采访计划

    时间限制: 2000 ms         内存限制: 131072 KB

    【题目描述】

    公元2044年,人类将进入宇宙纪元。L国有n个星球,分别编号为1到n,每一星球上有一个球长。

    因为历史的长期积淀,第i个星球上还有一位编号为i的德高望重的长者,因为长者德高望重,所以第i个星球的球长一定被第i位长者管辖且长者管辖自己。

    每一位长者手里有一份名单Bi,上面记录着一些长者的编号。

    因为一些奥妙重重的原因,第i位长者的名单上只可能有1至i-1中的一些编号并且保证不会重复。

    因为长者都德高望重,所以第i位长者管辖第j位长者的充要条件是:对于每一个k属于Bi,第k位长者管辖第j位长者。

    此时,有一位记者想对一些球长进行采访,为了保证采访顺利,他决定先与一些长者搞好关系,以便采访被这些长者管辖的球长。

    为了与更多的球长谈笑风生,这位记者会给你提出m个询问。

    第i个询问中记者会给你fi个长者的编号,你需要回答有多少个星球的球长至少直接或间接被一位长者管辖。m≤2000000 。

    【输入】

    第一行一个数n,表示星球的个数。

    接下来n行,每一行描述一个Bi:首先给出Bi的大小szi(可能为0),接下来szi个数,描述Bi中的每一个元素。保证Bi中的数没有重复。

    接下来一行,给出一个数m,表示询问的个数。

    接下来m行,每一行描述一个询问:格式同上文对于集合Bi的格式。

    【输出】

    共m行,第i行输出第i次询问的答案。

    【输入样例】

    7
    0
    1 1
    1 1
    1 2
    2 2 3
    0
    2 2 6
    3
    2 2 3
    2 3 5
    2 4 5

    【输出样例】

    3
    3
    4

    【提示】

    【样例解释】

    对于第一个询问,2、3号长者都管辖1号长者,所以总共有3个球长可以被采访,编号分别为1,2,3。

    对于第二个询问,3、5号长者都管辖1号长者,所以总共有3个球长可以被采访,编号分别为1,3,5。

    对于第三个询问,4号长者管辖第1、2号长者,所以总共有4个球长可以被采访,编号分别为1,2,4,5。

    特别说明:第5号长者没有管辖长者2,因为3∈B5但2不属于B3。但长者4管辖长者2,因为长者管辖自己。
        

    说明:

    图中省略了球长,编号代表长者有向边u→v表示u在Bv中

    【数据规模及约定】

    对于30%的数据,n,m≤100。


    对于100%的数据,n,m≤200000,∑|Bi|≤2000000,询问中的∑|szi|≤2000000 。

    【题解】

    这题关键在于如何建树,发现如果令一个点的所有祖先均被他管辖,则第i个节点应该接到它名单中节点的lca下,因为需要被这些点都管辖。

    边建树边倍增,建树复杂度nlogn。

    考虑如何回答询问。

    发现每个询问就是求给出所有点到根的并的节点数。考虑将所有节点按dfn排序,则将每个节点与其相邻的节点的lca加起来即为答案。

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=2e5+5;
    int n,last[N],size,f[N][20],m,dfn[N],hu[N],dep[N],cnt;
    struct pigu
    {
        int dao,ne;
    }a[N<<1];
    inline void lingjiebiao(int x,int y)
    {
        a[++size].dao=y;
        a[size].ne=last[x];
        last[x]=size;
    }
    inline int read()
    {
        int x=0,f=1;
        char c=getchar();
        while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();} 
        while(isdigit(c)) {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
        return x*f;
    }
    inline void lian(int x,int y)
    {
        f[x][0]=y;dep[x]=dep[y]+1;lingjiebiao(y,x);
        for(int i=1;f[f[x][i-1]][i-1];i++) f[x][i]=f[f[x][i-1]][i-1];
    }
    inline int get_lca(int x,int y)
    {
        if(dep[x]<dep[y])
            swap(x,y);
        for(int i=19;i>=0;i--)
            if(dep[f[x][i]]>=dep[y]) 
                x=f[x][i];
        if(x==y) return x;
        for(int i=19;i>=0;i--)
            if(f[x][i]!=f[y][i])
                x=f[x][i],y=f[y][i];
        return f[x][0];
    }
    inline void dfs(int now)
    {
        dfn[now]=++cnt;
        for(int i=last[now];i;i=a[i].ne) dfs(a[i].dao);
    }
    inline bool cmp(int x,int y)
    {
        return dfn[x]<dfn[y];
    }
    int main()
    {
        n=read();
        for(int i=1,x;i<=n;i++)
        {
            x=read();
            int lca=0;
            if(x) lca=read();
            for(int j=1,y;j<=x-1;j++)
            {
                y=read();
                lca=get_lca(lca,y);
            }
            lian(i,lca);
        }
        m=read();
        dfs(0);
        for(int i=1,x;i<=m;i++)
        {
            x=read();
            for(int j=1;j<=x;j++) hu[j]=read();
            sort(hu+1,hu+x+1,cmp);
            int ans=dep[hu[1]];
            for(int j=2;j<=x;j++) ans+=dep[hu[j]]-dep[get_lca(hu[j],hu[j-1])];
            cout<<ans<<"
    ";
        }
    }
    View Code
  • 相关阅读:
    (转)java反射机制及简单工厂模式
    (转)JAVA反射机制理解
    (转)前缀、中缀、后缀表达式
    (转)java提高篇(四)-----理解java的三大特性之多态
    (转)java for循环的执行顺序和几种常用写法
    (转)JAVA堆栈操作
    POI 实现合并单元格以及列自适应宽度
    前端缓存支持的文件格式及请求方式
    freemarker在xml文件中遍历list数据
    freemarker在线编辑
  • 原文地址:https://www.cnblogs.com/betablewaloot/p/12207941.html
Copyright © 2011-2022 走看看