2 条题解

  • 0
    @ 2025-10-8 17:03:11
    /*【参考程序】
    此题隐含的割点的思想。 
    siz[x]表示以x为根的搜索树的大小。 
    删掉的点x后,则增加的不连通有序对数量可分为3部分:
    统计原则:独立的点集与“外界点集 ”相乘。 
    1、若子树y满足dfn[x]<=low[y](子树y独立),则增加Size[y]* (n - siz[y])
    2、点x和外界:1*(n-1)
    3、外界 和 x+所有独立搜索树:(n-1-sum)*(sum+1)(sum= ∑(siz[y]),y是独立子树的根节点)
    */
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int N=1e5+10;
    vector<pair<int, int>> G[N];
    int n, m, tsp, low[N], dfn[N], siz[N];
    LL ans[N];
    void tarjan(int x, int in_id)
    {
    	dfn[x] = low[x] = ++tsp; siz[x] = 1; 
    	int sum = 0;
        for(auto i : G[x]) if(i.second != in_id)
        {
            int y = i.first, id = i.second;
            if(dfn[y] == 0)
            {
                tarjan(y, id);
                siz[x] += siz[y];
                low[x] = min(low[x], low[y]);
                if(dfn[x] <= low[y])
                {
                	ans[x] += (LL)siz[y] * (n - siz[y]);
                	sum += siz[y];
                }
            }
            else low[x] = min(low[x], dfn[y]);
        }
    	ans[x] += n - 1;
        ans[x] += (LL)(n - 1 - sum) * (sum + 1);
    }
    int main()
    {
    	scanf("%d%d", &n, &m);
    	for(int i=1, x, y; i <= m; i++)
    	{
    		scanf("%d%d", &x, &y); if(x == y) continue;
    		G[x].push_back({y, i});
    		G[y].push_back({x, i});
    	}
    	tsp = 0; memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low));
        memset(ans, 0, sizeof(ans)); memset(siz, 0, sizeof(siz));
    	for(int i=1; i <= n; i++) if(dfn[i] == 0) tarjan(i, 0);
    	for(int i=1; i <= n; i++) printf("%lld\n", ans[i]);
    	return 0;
    }
    
    /*【参考程序】
    此题隐含的割点的思想。 
    siz[x]表示以x为根的搜索树的大小。 
    删掉的点x后,则增加的不连通有序对数量可分为3部分:
    统计原则:独立的点集与“外界点集 ”相乘。 
    1、若子树y满足dfn[x]<=low[y](子树y独立),则增加Size[y]* (n - siz[y])
    2、点x和外界:1*(n-1)
    3、外界 和 x+所有独立搜索树:(n-1-sum)*(sum+1)(sum= ∑(siz[y]),y是独立子树的根节点)
    */
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int N=1e5+10;
    vector<int> G[N];
    int n, m, tsp, low[N], dfn[N], siz[N];
    LL ans[N];
    void tarjan(int x, int fa)
    {
    	dfn[x] = low[x] = ++tsp; siz[x] = 1; 
    	int sum = 0;
        for(int y : G[x]) if(y != fa)
        {
            if(dfn[y] == 0)
            {
                tarjan(y, x);
                siz[x] += siz[y];
                low[x] = min(low[x], low[y]);
                if(dfn[x] <= low[y])
                {
                	ans[x] += (LL)siz[y] * (n - siz[y]);
                	sum += siz[y];
                }
            }
            else low[x] = min(low[x], dfn[y]);
        }
    	ans[x] += n - 1;
        ans[x] += (LL)(n - 1 - sum) * (sum + 1);
    }
    int main()
    {
    	scanf("%d%d", &n, &m);
    	for(int i=1, x, y; i <= m; i++)
    	{
    		scanf("%d%d", &x, &y); if(x == y) continue;
    		G[x].push_back(y);
    		G[y].push_back(x);
    	}
    	tsp = 0; memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low));
        memset(ans, 0, sizeof(ans)); memset(siz, 0, sizeof(siz));
    	for(int i=1; i <= n; i++) if(dfn[i] == 0) tarjan(i, 0);
    	for(int i=1; i <= n; i++) printf("%lld\n", ans[i]);
    	return 0;
    }
    
    • 0
      @ 2025-10-8 17:02:52

      20241219尝试教的新代码:

      /*【参考程序】
      此题隐含的割点的思想。 
      siz[x]表示以x为根的搜索树的大小。 
      删掉的点x后,则增加的不连通有序对数量可分为3部分:
      统计原则:独立的点集与“外界点集 ”相乘。 
      1、若子树y满足dfn[x]<=low[y](子树y独立),则增加Size[y]* (n - siz[y])
      2、点x和外界:1*(n-1)
      3、外界 和 x+所有独立搜索树:(n-1-sum)*(sum+1)(sum= ∑(siz[y]),y是独立子树的根节点)
      */
      #include<bits/stdc++.h>
      using namespace std;
      typedef long long LL;
      const int N=1e5+10;
      vector<pair<int,int>>G[N];
      int n,m,tsp,low[N],dfn[N],siz[N];
      LL ans[N];
      void tarjan(int x,int in_id)
      {
      	dfn[x]=low[x]=++tsp;siz[x]=1; 
      	int sum=0;
          for(auto i:G[x]) if(i.second!=in_id)
          {
              int y=i.first,id=i.second;
              if(dfn[y]==0)
              {
                  tarjan(y,id);
                  siz[x]+=siz[y];
                  low[x]=min(low[x], low[y]);
                  if(dfn[x]<=low[y])
                  {
                  	ans[x]+=(LL)siz[y]*(n-siz[y]);
                  	sum+=siz[y];
                  }
              }
              else low[x]=min(low[x], dfn[y]);
          }
      	ans[x]+=n-1;
          ans[x]+=(LL)(n-1-sum)*(sum+1);
      }
      int main()
      {
      	scanf("%d%d",&n,&m);
      	for(int i=1,x,y;i<=m;i++)
      	{
      		scanf("%d%d",&x,&y);if(x==y)continue;
      		G[x].push_back({y,i});
      		G[y].push_back({x,i});
      	}
      	tsp=0;memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));
          memset(ans,0,sizeof(ans));memset(siz,0,sizeof(siz));
      	for(int i=1;i<=n;i++)if(dfn[i]==0)tarjan(i,0);
      	for(int i=1;i<=n;i++)printf("%lld\n",ans[i]);
      	return 0;
      }
      

      /*【参考程序】
      此题隐含的割点的思想。 
      siz[x]表示以x为根的搜索树的大小。 
      删掉的点x后,则增加的不连通有序对数量可分为3部分:
      统计原则:独立的点集与“外界点集 ”相乘。 
      1、若子树y满足dfn[x]<=low[y](子树y独立),则增加Size[y]* (n - siz[y])
      2、点x和外界:1*(n-1)
      3、外界 和 x+所有独立搜索树:(n-1-sum)*(sum+1)(sum= ∑(siz[y]),y是独立子树的根节点)
      */
      #include<bits/stdc++.h>
      using namespace std;
      typedef long long LL;
      const int N=1e5+10;
      vector<int>G[N];
      int n,m,tsp,low[N],dfn[N],siz[N];
      LL ans[N];
      void tarjan(int x,int fa)
      {
      	dfn[x]=low[x]=++tsp;siz[x]=1; 
      	int sum=0;
          for(int y:G[x]) if(y!=fa)
          {
              if(dfn[y]==0)
              {
                  tarjan(y,x);
                  siz[x]+=siz[y];
                  low[x]=min(low[x], low[y]);
                  if(dfn[x]<=low[y])
                  {
                  	ans[x]+=(LL)siz[y]*(n-siz[y]);
                  	sum+=siz[y];
                  }
              }
              else low[x]=min(low[x], dfn[y]);
          }
      	ans[x]+=n-1;
          ans[x]+=(LL)(n-1-sum)*(sum+1);
      }
      int main()
      {
      	scanf("%d%d",&n,&m);
      	for(int i=1,x,y;i<=m;i++)
      	{
      		scanf("%d%d",&x,&y);if(x==y)continue;
      		G[x].push_back(y);
      		G[y].push_back(x);
      	}
      	tsp=0;memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));
          memset(ans,0,sizeof(ans));memset(siz,0,sizeof(siz));
      	for(int i=1;i<=n;i++)if(dfn[i]==0)tarjan(i,0);
      	for(int i=1;i<=n;i++)printf("%lld\n",ans[i]);
      	return 0;
      }
      • 1

      信息

      ID
      2776
      时间
      2000ms
      内存
      64MiB
      难度
      6
      标签
      递交数
      45
      已通过
      13
      上传者