给定一个 个点 条边的无向图,每条边有流量 ,保证其是一个逆时针从 到 编号的正 边形,且边只会在顶点处相交,求 个点两两间的最大流之和,对 取模。
,,。
由于这是一个平面图,所以最大流=最小割=对偶图最短路。
具体的,从每个顶点向多边形外面引一条射线,则 到 的最大流相当于对偶图上两区间的点之间的最短路:

考虑多边形外圈权值最小的边 及其所在的最小环 :

有一个性质:
- 最短路一定会经过 的 条或 条边;
- 若最短路经过 的 条边,则一定可以经过 ;
第一条显然,因为有进有出,而且不可能走回头路。
第二条是因为 在外围,所以通过更换最短路起点或终点,将最短路经过的 上的边换成 一定不劣。
那么根据这个性质,我们可以每次找到外围边权最小的边 ,将 加到它所在最小环上的其它边上,然后删掉 。不难发现新图最大流不变。
那么不断进行这样的删边操作,最后图会变成一棵树。而树的最大流=最小割就相当于两点间路径上边权最小值,可以快速计算。
时间复杂度 。
具体实现可以考虑建出对偶图。
代码如下:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <set>
#include <queue>
using namespace std;
typedef long long ll;
const int S=200005,p=998244353;
struct node
{
	int x,y;
	ll w;
}ed[S*2];
int n,m;
vector<pair<int,int> > gg[S];
set<pair<int,int> > g[S*4];
bool flg[S*4],vis[S*4];
vector<node> g2;
int fa[S],siz[S];
int fnd(int x)
{
	return fa[x]==x?x:fa[x]=fnd(fa[x]);
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int x,y,w;
		scanf("%d%d%d",&x,&y,&w);
		if(x>y) swap(x,y);
		ed[i]=(node){x,y,w};
		gg[x].emplace_back(y,i);
	}
	for(int i=1;i<=n;i++) sort(gg[i].begin(),gg[i].end());
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<gg[i].size();j++)
		{
			int u=gg[i][j].second,rb=gg[i][j].first;
			int v=gg[i][j-1].second,p=gg[i][j-1].first;
			if(i==1&&rb==n)
			{
				m++;
				g[u].emplace(m,u);
				g[m].emplace(u,u);
			}
			g[u].emplace(v,v);
			g[v].emplace(u,v);
			while(p!=rb)
			{
				auto tmp=*gg[p].rbegin();
				int v=tmp.second;
				p=tmp.first;
				g[u].emplace(v,v);
				g[v].emplace(u,v);
			}
		}
	}
	priority_queue<pair<ll,int> > q;
	for(int i=1;i<=m;i++)
	{
		if(g[i].size()==1)
		{
			flg[i]=true;
			int id=g[i].begin()->second;
			q.emplace(-ed[id].w,i);
		}
	}
	while(!q.empty())
	{
		auto t=q.top();
		q.pop();
		int u=t.second;
		if(vis[u]) continue;
		ll w=-t.first;
		int fa=g[u].begin()->first;
		for(auto t:g[fa])
		{
			int v=t.first,id=t.second;
			ed[id].w+=w;
			g[v].erase(make_pair(fa,id));
			if(flg[v])
			{
				vis[v]=true;
				if(v!=u)
				{
					int x=ed[id].x,y=ed[id].y;
					ll w=ed[id].w;
					g2.push_back((node){x,y,w});
				}
			}
			else
			{
				m++;
				flg[m]=true;
				g[m].emplace(v,id);
				g[v].emplace(m,id);
				q.emplace(-ed[id].w,m);
			}
		}
	}
	sort(g2.begin(),g2.end(),[&](node x,node y){
		return x.w>y.w;
	});
	for(int i=1;i<=n;i++) fa[i]=i,siz[i]=1;
	ll ans=0;
	for(auto t:g2)
	{
		int x=fnd(t.x),y=fnd(t.y);
		ll w=t.w;
		if(x==y) continue;
		ans+=w%p*siz[x]*siz[y]%p;
		siz[y]+=siz[x];
		fa[x]=y;
	}
	ans%=p;
	printf("%lld\n",ans);
	return 0;
}
