2 条题解

  • 0
    @ 2026-6-13 21:28:59

    // SCC 缩点 Tarjan 算法 O(N)
    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    
    const int N=100010;
    vector<int> e[N],ee[N];
    int n,m,mod;
    int dfn[N],low[N],stk[N],top,scc[N],siz[N],cnt;
    int d[N],f[N],mx,sum;
    
    void tarjan(int x){ //SCC缩点
      dfn[x]=low[x]=++dfn[0]; stk[++top]=x;
      for(auto y:e[x]){
        if(!dfn[y]) tarjan(y),low[x]=min(low[x],low[y]);
        else if(!scc[y]) low[x]=min(low[x],dfn[y]); 
      }
    
      if(dfn[x]==low[x]){
        ++cnt;
        while(stk[top+1]!=x) scc[stk[top--]]=cnt,siz[cnt]++;
      }
    }
    int main(){
      scanf("%d%d%d",&n,&m,&mod);
      for(int a,b;m--;) scanf("%d%d",&a,&b),e[a].push_back(b);
      
      for(int i=1; i<=n; i++)if(!dfn[i]) tarjan(i); //SCC缩点
      
      unordered_set<ll> S; //哈希表判重边
      for(int x=1; x<=n; x++)for(auto y:e[x]){ //枚举每个点的邻接点
        int a=scc[x],b=scc[y];
        ll hash=a*1000000ll+b; //端点的哈希值
        if(a!=b && !S.count(hash)){ //不在一个SCC且边(a,b)没被加过
          ee[a].push_back(b); //缩点之间连边
          S.insert(hash); //记录哈希值
        }
      }
      
      for(int x=cnt; x; x--){ //枚举缩点
        if(d[x]==0){ //拓扑图起点
          d[x]=siz[x];
          mx=max(mx,d[x]);
          f[x]=1;
        }
        for(auto y:ee[x]){ //枚举邻接点
          if(d[y]<d[x]+siz[y]){
            d[y]=d[x]+siz[y]; //更新最长路
            mx=max(mx,d[y]);
            f[y]=f[x]; //继承方案数
          }
          else if(d[y]==d[x]+siz[y]){
            f[y]=(f[y]+f[x])%mod; //更新方案数
          }
        }
      }
      
      for(int i=1; i<=cnt; i++) //枚举缩点
        if(d[i]==mx) sum=(sum+f[i])%mod; //累加最长路的方案数
      printf("%d\n%d\n",mx,sum);
    }
    
    • 0
      @ 2025-10-8 17:03:04
      #include <bits/stdc++.h> 
      using namespace std;
      const int N=110000;
      vector<int> G1[N], G2[N];
      int tsp, cnt, low[N], dfn[N], scc[N], num[N];
      stack<int> stk; bool instk[N];
      void tarjan(int x)
      {
      	dfn[x] = low[x] = ++tsp;
      	stk.push(x); instk[x] = 1;
          for(int y : G1[x]) 
          {
              if(dfn[y] == 0)
              {
                  tarjan(y);
                  low[x] = min(low[x], low[y]);
              }
              else if(instk[y]) low[x] = min(low[x], dfn[y]);
          }
          if(low[x] == dfn[x]) 
          {
              cnt++;
              for(int z = -1; z != x;) {
      			z = stk.top(); stk.pop(); instk[z] = 0;
                  scc[z] = cnt;
                  num[cnt]++;
              }
      
          }
      }
      
      int main()
      {
          int n, m, X; scanf("%d%d%d", &n, &m, &X);
          memset(G1, 0, sizeof(G1));
          for(int i=1, x, y; i <= m; i++) scanf("%d%d", &x, &y), G1[x].push_back(y);
          
          tsp = cnt = 0; memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low));
          memset(instk,0,sizeof(instk)); memset(scc,0,sizeof(scc)); memset(num,0,sizeof(num));
          for(int i=1; i <= n; i++) if(dfn[i] == 0) tarjan(i);
      
          map<pair<int, int>, bool> mp;
          vector<int> rd(cnt + 1);
          for(int i=1; i <= n; i++) for(int j : G1[i])
          {
              int x = scc[i], y = scc[j];
              if(x != y && !mp[{x, y}]) G2[x].push_back(y), rd[y]++, mp[{x, y}] = true;
          }
      
          vector<int> d(cnt + 1), C(cnt + +1);;
          for(int i=1; i <= cnt; i++) d[i] = num[i], C[i] = 1;
          deque<int> q; for(int i=1; i <= cnt; i++) if(rd[i] == ) q.push_back(i);
          while(!q.empty())
          {
              int x = q.front(); q.pop_front();
              for(int y : G2[x])
              {
                  rd[y]--; if(rd[y] == 0) q.push_back(y);
                  if(d[y] < d[x] + num[y]) d[y] = d[x] + num[y], C[y] = C[x];
                  else if(d[y] == d[x] + num[y]) C[y] = (C[y] + C[x]) % X;
              }
          }
          
          int maxd = 0; for(int i=1; i <= cnt; i++) maxd = max(maxd, d[i]);
          int ansC = 0; for(int i=1; i <= cnt; i++) if(maxd == d[i]) ansC = (ansC + C[i]) % X;
          printf("%d\n%d\n", maxd, ansC);
          return 0;
      }
      
      • 1

      D160 【缩点】[ZJOI2007] 最大半连通子图

      信息

      ID
      2746
      时间
      1000ms
      内存
      256MiB
      难度
      7
      标签
      递交数
      113
      已通过
      25
      上传者