2 条题解

  • 0
    @ 2025-10-8 17:00:07
    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e6+10, inf=1e9;
    int a[N], b[N], dep[N], fa[N], del[N], id[N], tsp, dfn[N]; 
    int siz[N], n, m; vector<int> G[N];
    int findfa(int x) {return (fa[x]==x)? fa[x]: fa[x]=findfa(fa[x]);}
    bool pd1(int x, int y){
        int tx=findfa(x), ty=findfa(y); 
        if(tx!=ty) {fa[tx]=ty; return 0;}
        else return 1;
    }
    void dfs(int x){
        dfn[x]=++tsp; siz[x]=1;
        for(int y: G[x]){
            dep[y]=dep[x]+1;
            id[y]=id[x];
            dfs(y);
            siz[x]+=siz[y];
        }
    }
    bool pd2(int x, int y){   
        return ((dfn[x]>=dfn[y]) && (dfn[x]<=dfn[y]+siz[y]-1)); //x在y的子树内
    }
    int query(int x, int y){
        if(x==y) return 0;
        if(id[x]!=id[y]) return inf;
        int res=inf;
        if(pd2(x, y)) res=min(res, dep[x]-dep[y]); //x是y的子节点
        if(pd2(del[id[y]], y)) res=min(res, dep[del[id[y]]]-dep[y]+dep[x]+1); 
        //通过那条断的边走到环上的y,答案为环上的路径加x到环上那个节点的路径加短边
        return res;
    }
    bool check(int x){
        int i, w;
        for(i=1, w=1; i<=n, w<=m;){
            if(query(a[i], w)<=x) i++;
            else w++;
        }
        return i>n;
    }
    int main(){
        freopen("a.in", "r", stdin);
        int T; scanf("%d", &T);
        while(T--){
            scanf("%d%d", &n, &m);
            for(int i=1; i<=m; i++){
                G[i].clear(); dep[i]=0; fa[i]=i;
                del[i]=0; id[i]=0; del[0]=0; dfn[i]=0;
            }
            for(int i=1; i<=n; i++) scanf("%d", &a[i]);
            for(int i=1; i<=m; i++){
                scanf("%d", &b[i]);
                if(pd1(b[i], i)==0) G[b[i]].push_back(i);
                else del[i]=b[i]; //有环,断这条边
            }
            tsp=0; 
            for(int i=1; i<=m; i++) 
                if(del[i]) id[i]=i, dfs(i);
            int l=0, r=m, p=-1;
            while(l<=r){
                int mid=(l+r)/2;
                if(check(mid)) r=mid-1, p=mid;
                else l=mid+1;
            }
            printf("%d\n", p);
        }
        return 0;
    }
    
    • 0
      @ 2025-10-8 16:59:54
      #include<bits/stdc++.h>
      using namespace std;
      const int N=1e6+10, inf=1e9;
      int a[N], b[N], dep[N], fa[N], del[N], id[N], tsp, dfn[N]; 
      int siz[N], n, m; vector<int> G[N];
      int findfa(int x) {return (fa[x]==x)? fa[x]: fa[x]=findfa(fa[x]);}
      bool pd1(int x, int y){
          int tx=findfa(x), ty=findfa(y); 
          if(tx!=ty) {fa[tx]=ty; return 0;}
          else return 1;
      }
      void dfs(int x){
          dfn[x]=++tsp; siz[x]=1;
          for(int y: G[x]){
              dep[y]=dep[x]+1;
              id[y]=id[x];
              dfs(y);
              siz[x]+=siz[y];
          }
      }
      bool pd2(int x, int y){   
          return ((dfn[x]>=dfn[y]) && (dfn[x]<=dfn[y]+siz[y]-1)); //x在y的子树内
      }
      int query(int x, int y){
          if(x==y) return 0;
          if(id[x]!=id[y]) return inf;
          int res=inf;
          if(pd2(x, y)) res=min(res, dep[x]-dep[y]); //x是y的子节点
          if(pd2(del[id[y]], y)) res=min(res, dep[del[id[y]]]-dep[y]+dep[x]+1); 
          //通过那条断的边走到环上的y,答案为环上的路径加x到环上那个节点的路径加短边
          return res;
      }
      bool check(int x){
          int i, w;
          for(i=1, w=1; i<=n, w<=m;){
              if(query(a[i], w)<=x) i++;
              else w++;
          }
          return i>n;
      }
      int main(){
          freopen("a.in", "r", stdin);
          int T; scanf("%d", &T);
          while(T--){
              scanf("%d%d", &n, &m);
              for(int i=1; i<=m; i++){
                  G[i].clear(); dep[i]=0; fa[i]=i;
                  del[i]=0; id[i]=0; del[0]=0; dfn[i]=0;
              }
              for(int i=1; i<=n; i++) scanf("%d", &a[i]);
              for(int i=1; i<=m; i++){
                  scanf("%d", &b[i]);
                  if(pd1(b[i], i)==0) G[b[i]].push_back(i);
                  else del[i]=b[i]; //有环,断这条边
              }
              tsp=0; 
              for(int i=1; i<=m; i++) 
                  if(del[i]) id[i]=i, dfs(i);
              int l=0, r=m, p=-1;
              while(l<=r){
                  int mid=(l+r)/2;
                  if(check(mid)) r=mid-1, p=mid;
                  else l=mid+1;
              }
              printf("%d\n", p);
          }
          return 0;
      }
      • 1

      不降路径[CF1967D]Long Way to be Non-decreasing

      信息

      ID
      2120
      时间
      4000ms
      内存
      512MiB
      难度
      10
      标签
      递交数
      6
      已通过
      4
      上传者