2 条题解

  • 0
    @ 2025-10-8 16:59:56

    可以发现,答案就是路径上可能经过的点数。 考虑将图缩成圆方树,统计树上路径点数。 可以简单发现,如果将方点的权值标为点双大小,圆点的权值标为-1, 则某条路径上可能经过的点数就是圆方树上路径点权和。 直接做是O(n²)的,但是可以改为统计每个点被经过多少次再乘上它的权值,可以利用简单 dfs+dp做到O(n)。

    /*
    可以发现,答案就是路径上可能经过的点数。
    考虑将图缩成圆方树,统计树上路径点数。
    可以简单发现,如果将方点的权值标为点双大小,圆点的权值标为-1,
    则某条路径上可能经过的点数就是圆方树上路径点权和。
    直接做是O(n^2)的,但是可以改为统计每个点被经过多少次再乘上它的权值,可以利用简单
    dfs+dp做到O(n)。
    */
    
    #include<iostream>
    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+10;
    vector<int>G1[N],G2[N<<1];
    int n,m,tsp,cnt,dfn[N],low[N],num,wgh[N<<1],siz[N<<1];
    stack<int>stk;
    long long ans;
    
    void tarjan(int x)
    {
    	dfn[x]=low[x]=++tsp;
    	stk.push(x);
    	++num;
    	for(int y:G1[x])
    	{
    		if(!dfn[y])
    		{
    			tarjan(y);
    			low[x]=min(low[x],low[y]);
    			if(dfn[x]==low[y])
    			{
    				cnt++;
    				wgh[cnt]=0;
    				G2[x].push_back(cnt);++wgh[cnt];
    				for(int z=-1;z!=y;)
    				{
    					z=stk.top();stk.pop();
    					G2[cnt].push_back(z);++wgh[cnt];
    				}
    			}
    		}
    		else low[x]=min(low[x],dfn[y]);
    	}
    }
    
    void dfs(int x)
    {
    	siz[x]=(x<=n);
    	long long t=0; 
    	for(int y:G2[x])
    	{
    		dfs(y);
    		t+=2ll*siz[x]*siz[y];
    		siz[x]+=siz[y];
    	}
    	t+=2ll*siz[x]*(num-siz[x]);
    	ans+=t*wgh[x];
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++) wgh[i]=-1;
    	for(int i=1,x,y;i<=m;i++)
    	{
    		scanf("%d%d",&x,&y);
    		G1[x].push_back(y);
    		G1[y].push_back(x);
    	}
    	tsp=0;cnt=n;memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));
    	ans=0;
    	for(int i=1;i<=n;i++) if(!dfn[i])
    	{
    		num=0;
    		tarjan(i);stk.pop();
    		dfs(i);
    	} 
    	printf("%lld\n",ans);
    	return 0;
    }
    
    • 0
      @ 2025-10-8 16:59:41
      /*
      可以发现,答案就是路径上可能经过的点数。
      考虑将图缩成圆方树,统计树上路径点数。
      可以简单发现,如果将方点的权值标为点双大小,圆点的权值标为-1,
      则某条路径上可能经过的点数就是圆方树上路径点权和。
      直接做是O(n^2)的,但是可以改为统计每个点被经过多少次再乘上它的权值,可以利用简单
      dfs+dp做到O(n)。
      */
      
      #include<bits/stdc++.h>
      using namespace std;
      const int N=1e5+10;
      vector<int>G1[N],G2[N<<1];
      int n,m,tsp,cnt,dfn[N],low[N],num,wgh[N<<1],siz[N<<1];
      stack<int>stk;
      long long ans;
      
      void tarjan(int x)
      {
      	dfn[x]=low[x]=++tsp;
      	stk.push(x);
      	++num;
      	for(int y:G1[x])
      	{
      		if(!dfn[y])
      		{
      			tarjan(y);
      			low[x]=min(low[x],low[y]);
      			if(dfn[x]==low[y])
      			{
      				cnt++;
      				wgh[cnt]=0;
      				G2[x].push_back(cnt);++wgh[cnt];
      				for(int z=-1;z!=y;)
      				{
      					z=stk.top();stk.pop();
      					G2[cnt].push_back(z);++wgh[cnt];
      				}
      			}
      		}
      		else low[x]=min(low[x],dfn[y]);
      	}
      }
      
      void dfs(int x)
      {
      	siz[x]=(x<=n);
      	long long t=0; 
      	for(int y:G2[x])
      	{
      		dfs(y);
      		t+=2ll*siz[x]*siz[y];
      		siz[x]+=siz[y];
      	}
      	t+=2ll*siz[x]*(num-siz[x]);
      	ans+=t*wgh[x];
      }
      int main()
      {
      	scanf("%d%d",&n,&m);
      	for(int i=1;i<=n;i++) wgh[i]=-1;
      	for(int i=1,x,y;i<=m;i++)
      	{
      		scanf("%d%d",&x,&y);
      		G1[x].push_back(y);
      		G1[y].push_back(x);
      	}
      	tsp=0;cnt=n;memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));
      	ans=0;
      	for(int i=1;i<=n;i++) if(!dfn[i])
      	{
      		num=0;
      		tarjan(i);stk.pop();
      		dfs(i);
      	} 
      	printf("%lld\n",ans);
      	return 0;
      }
      • 1

      信息

      ID
      2036
      时间
      1000ms
      内存
      1024MiB
      难度
      7
      标签
      递交数
      64
      已通过
      16
      上传者