CodeForces 466E. Information Graph (并查集+倍增)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jerry99s/article/details/84653533

题目: http://codeforces.com/problemset/problem/466/E

题意:
三种操作:
1.y变为x的boss;
2.x签署一份文件并逐级往上传并签署;
3.查询第x个人是否签署第i份文件。

分析:
在线变离线;
用路径压缩的并查集能直接查询当前状态下某个人的最高boss;
签署一份文件时,记录签署此文件最底端的人和最顶端的人;
倍增处理出每个节点往上走1<<i步是谁;
处理出每个节点的深度deep[i]。

对于每个查询:
从第i个文件的最底端往上走(deep[x]-deep[i文件底端])步;
并查询走到的这个节点是否为x。

代码:

//jerry99
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int tmax=1e5+5;
int n,m,fa[tmax][20],f[tmax],deep[tmax];
int Start[tmax],End[tmax],num,numq;
struct node{
    int people,packnum;
};
node q[tmax];
vector<int> G[tmax];
int find(int x)
{
    return f[x]==x?x:f[x]=find(f[x]);
}
void dfs(int x,int d)
{
    deep[x]=d;
    int i,len=G[x].size();
    for(i=0;i<len;i++)
        dfs(G[x][i],d+1);
    return;
}
void init()
{
    int i,j;
    for(j=1;j<=17;j++)
        for(i=1;i<=n;i++)
            fa[i][j]=fa[fa[i][j-1]][j-1];
    for(i=1;i<=n;i++)
        if(find(i)==i)
            dfs(i,1);
    return;
}
void work()
{
    int i,j,Dif,s,t,check;
    for(j=1;j<=numq;j++)
    {
        s=Start[q[j].packnum];
        t=End[q[j].packnum];
        check=q[j].people;
        //printf("s=%d t=%d\n",s,t);
        if(find(s)!=find(check)||deep[s]<deep[check]||deep[check]<deep[t])
        {
            printf("NO\n");
            continue;
        }
        Dif=deep[s]-deep[check];
        for(i=17;i>=0;i--)
        {
            if(Dif<(1<<i)) continue;
            Dif-=(1<<i);
            s=fa[s][i];
            if(s==0) break;
        }
        if(s!=check) printf("NO\n");
        else printf("YES\n");
    }
    return;
}
int main()
{
    scanf("%d%d",&n,&m);
    int i,t,x,y;
    for(i=1;i<=n;i++)
        f[i]=i;
    for(i=1;i<=m;i++)
    {
        scanf("%d",&t);
        if(t==1)
        {
            scanf("%d%d",&x,&y);
            fa[x][0]=y;
            G[y].push_back(x);
            f[x]=find(y);
        }
        else if(t==2)
        {
            num++;
            scanf("%d",&Start[num]);
            End[num]=find(Start[num]);
        }
        else
        {
            numq++;
            scanf("%d%d",&q[numq].people,&q[numq].packnum);
        }
    }
    init();
    work();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/jerry99s/article/details/84653533