把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P4214 [CERC2015]Juice Junctions

题面传送门

看到这道题的第一眼想法是这不是最小割树裸题吗,直接跑出最小割树然后暴力O(n2)算答案就好了。

但是仔细想想似乎不是很对,因为你实际上这样跑网络流虽然是O(n+m)的但是还带个3倍常数,实际上Dicnic的常数还死大的……

我们考虑分类讨论,先算最小割至少为1的,显然就是一个联通块内部的点。

然后再算最小割至少为2的,可以发现两个点之间如果没有割边那么这两个点至少要割掉两条边。因此只需要求一个边双即可。

然后算最小割至少为3的,任意割掉一条边以后,一对点总是在一个边双内的点对显然要三条,否则两条。则枚举割掉的那条边然后暴力边双即可。然后要判断集合相等,显然哈希即可。

时间复杂度O(nm),听说边三联通分量能做到O(n+m)/xia

code:

#include<bits/stdc++.h>
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((m)*(x-1)+(y))
#define R(n) (rnd()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=4.5e3+5,M=N*4+5,K=1e5+5,mod=1e9+7,Mod=mod-1,INF=1e9+7;const db eps=1e-5;mt19937 rnd(time(0));
int Ans[N],n,m,k,x,y,z,X[N],Y[N],fa[N],Si[N],Ct,scc[N];ull f[N];
struct Edge{int x,id;};vector<Edge> S[N];
int GF(int x){return fa[x]^x?fa[x]=GF(fa[x]):x;}
namespace Tarjan{
	int low[N],dfn[N],st[N],sh,dh;
	void dfs(int x,int La){
		low[x]=dfn[x]=++dh;st[++sh]=x;for(Edge i:S[x])if(i.id^La){
			if(!dfn[i.x])dfs(i.x,i.id),low[x]=min(low[x],low[i.x]);
			else low[x]=min(low[x],dfn[i.x]);
		}if(low[x]==dfn[x]){++Ct;while(st[sh+1]^x) scc[st[sh]]=Ct,sh--;}
	}
	void GA(){Ct=0;sh=0;dh=0;Me(dfn,0);Me(st,0);Me(low,0);Me(scc,0);for(int i=1;i<=n;i++) !dfn[i]&&(dfs(i,0),0);}
}
ull P[N];map<ull,int> Ts;
int main(){
	freopen("1.in","r",stdin);
	int i,j,h;scanf("%d%d",&n,&m); for(i=1;i<=m;i++) scanf("%d%d",&X[i],&Y[i]),S[X[i]].PB((Edge){Y[i],i}),S[Y[i]].PB((Edge){X[i],i});
	for(i=1;i<=n;i++) fa[i]=i;for(i=1;i<=m;i++) fa[GF(X[i])]=GF(Y[i]);for(i=1;i<=n;i++) Si[GF(i)]++;
	for(i=1;i<=n;i++) Ans[i]+=Si[GF(i)];Me(Si,0);Tarjan::GA();for(i=1;i<=n;i++) Si[scc[i]]++;for(i=1;i<=n;i++) Ans[i]+=Si[scc[i]];
	for(i=1;i<=m;i++){
		for(auto j=S[X[i]].begin();j!=S[X[i]].end();j++) if((*j).x==Y[i]){S[X[i]].erase(j);break;} 
		for(auto j=S[Y[i]].begin();j!=S[Y[i]].end();j++) if((*j).x==X[i]){S[Y[i]].erase(j);break;}
		Tarjan::GA();S[X[i]].PB((Edge){Y[i],i});S[Y[i]].PB((Edge){X[i],i});
		for(j=1;j<=n;j++) f[j]=((ull)rnd()<<32)|rnd();for(j=1;j<=n;j++) P[j]^=f[scc[j]];
	}
	for(i=1;i<=n;i++) Ts[P[i]]++;for(i=1;i<=n;i++) printf("%d\n",Ans[i]+Ts[P[i]]-3);
}
posted @   275307894a  阅读(25)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
浏览器标题切换
浏览器标题切换end
点击右上角即可分享
微信分享提示