466E

这题说的是给了一个公司员工100000 然后现在又3种操作第一种将y置为x的父亲,第二种操作将文件给第x个人签他签完给他的上司签,一直到没有上司为止,第三种操作问x是否签了第i份文件,然后 我们只要直到每两个点在最后形成的这颗树的位置只有祖先关系第一类   叔叔兄弟和其他的归为另一类,然后我们通过并查集判断他们是否在同一颗树中如果在判断他们的关系可以用刚刚处理出来的关系

处理这个关系用的是 访问的时间差可以判断是否为这个节点的孩子 看下面的代码 tin[x]<=tin[y]&&tou[x]>=tou[y] 那么y一定是x的孩子或者是x

#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn =100005;
int tin[maxn],tou[maxn];
int tag[maxn];
vector<int>F[maxn];
int op[maxn],x[maxn],y[maxn];
int qusetion[maxn],time;
vector<int>ansquestion[maxn];
void dfs(int v, int p=-1){
     tin[v]=time++;
     int L=F[v].size();
     for(int i=0; i<L; ++i){
         int to = F[v][i];
         if(to==p) continue;
         dfs(to,v);
     }
     tou[v]=time++;
}
int per[maxn];
int fa(int a){
   return per[a]= a==per[a]?a:fa(per[a]);
}
void unin(int a, int b){
     a=fa(a); b=fa(b);
     if(a!=b) per[a]=b;
}
bool ans[maxn];
int paatt(int a,int b){
    return tin[a]<=tin[b]&&tou[a]>=tou[b];
}
int main()
{
     memset(ans,false,sizeof(ans));
     int n,m,number=0;
     scanf("%d%d",&n,&m);
     for(int i=0; i<m; ++i){
          scanf("%d",&op[i]);
          if(op[i]==2){
             scanf("%d",&x[i]);
          }else scanf("%d%d",&x[i],&y[i]);
          if(op[i]==1){
               F[y[i]].push_back(x[i]);
               tag[x[i]]++;
          }else if(op[i]==2){
               qusetion[i]=++number;
          }else {
                ansquestion[y[i]].push_back(i);
          }
     }
     time=1;
     for(int i=1; i<=n; ++i){
        if(tag[i]!=0||tin[i]!=0) continue;
        dfs(i);
     }
     for(int i=1; i<=n; ++i)
        per[i]=i;

     for(int i=0; i<m; ++i){
          if(op[i]==1){

             unin(x[i],y[i]);
          }else if(op[i]==2){
               int an= qusetion[i];
               int root=x[i];
               int L = ansquestion[an].size();
               for(int j=0; j<L; ++j){
                   int  to = ansquestion[an][j];
                   int  in=x[to];
                   ans[to]=fa(in)==fa(root)&&paatt(in,root);
               }
          }
     }
     for(int i=0; i<m; ++i)
         if(op[i]==3)
          printf("%s
",ans[i]?"YES":"NO");
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/Opaser/p/4001138.html