suxxsfe

一言(ヒトコト)

模板库-图论

图论

邻接表

struct Graph{
	int fir[N],nex[M],to[M],tot;
	inline void add(int u,int v,int flag=1){
		to[++tot]=v;nex[tot]=fir[u];fir[u]=tot;
		if(flag) add(v,u,0);
	}
	inline void clear(){std::memset(fir,0,sizeof fir);tot=0;}
}G;

dij 最短路

inline void dij(int u,int *dis,const Graph &G=::G){
	std::memset(dis,0x3f,(n+1)*sizeof dis[0]);dis[u]=0;
	static std::priority_queue<std::pair<int,int> >que;
	que.push(std::make_pair(0,u));
	while(!que.empty()){
		u=que.top().second;
		if(que.top().first^(-dis[u])){que.pop();continue;}
		que.pop();
		for(int v,i=G.fir[u];i;i=G.nex[i]){
			v=G.to[i];
			if(dis[v]<=dis[u]+G.w[i]) continue;
			dis[v]=dis[u]+G.w[i];que.push(std::make_pair(-dis[v],v));
		}
	}
}

tarjan 缩强连通分量

int dfn[N],low[N],dfscnt;
int stack[N],top;
int scc[N],scccnt;
void tarjan(int u){
	dfn[u]=low[u]=++dfscnt;
	stack[top++]=u;
	for(int v,i=G.fir[u];i;i=G.nex[i]){
		v=G.to[i];
		if(!dfn[v]){
			tarjan(v);
			low[u]=std::min(low[u],low[v]);
		}
		else if(!scc[v]) low[u]=std::min(low[u],dfn[v]);
	}
	if(dfn[u]==low[u]){
		scccnt++;
		do{
			scc[stack[--top]]=scccnt;
		}while(stack[top]^u);
	}
}

tarjan 求割点

int dfn[N],low[N],dfscnt;
int cut[N];
void tarjan(int u,int root){
	dfn[u]=low[u]=++dfscnt;
	int cnt=0;
	for(int v,i=G.fir[u];i;i=G.nex[i]){
		v=G.to[i];
		if(!dfn[v]){
			tarjan(v,root);
			low[u]=std::min(low[v],low[u]);
			if(low[v]>=dfn[u]&&u!=root) cut[u]=1;
			cnt++;
		}
		low[u]=std::min(low[u],dfn[v]);
	}
	if(cnt>1&&u==root) cut[u]=1;
}

tarjan 求桥

void tarjan(int u){
	dfn[u]=low[u]=++dfscnt;
	for(int v,i=G.fir[u];i;i=G.nex[i]){
		v=G.to[i];
		if(!dfn[v]){
			fa[v]=u;tarjan(v);
			low[u]=std::min(low[u],low[v]);
			if(low[v]>dfn[u]) bridge[v]=1,ans++;
		}
		else if(v!=fa[u]) low[u]=std::min(low[u],dfn[v]);
	}
}

st 表 \(O(n\log n)-O(1)\) 求 LCA

struct Graph{
	int fir[N],nex[M],to[M],tot;
	inline void add(int u,int v,int c,int flag=1){
		to[++tot]=v;nex[tot]=fir[u];fir[u]=tot;
		if(flag) add(v,u,0);
	}
	int st[20][N*2],log2[N*2];
	int dfscnt,dfn[N],id[N*2];
	int deep[N];
	void dfs(int u,int fa=0){
		deep[u]=deep[fa]+1;dfn[u]=++dfscnt;id[dfscnt]=u;
		for(int v,i=fir[u];i;i=nex[i]){
			v=to[i];
			if(v==fa) continue;
			sum[v]=sum[u]+w[i];
			dfs(v,u);id[++dfscnt]=u;
		}
	}
	inline int getLca(int u,int v){
		if(dfn[u]>dfn[v]) lib::swap(u,v);
		u=dfn[u];v=dfn[v];
		int len=log2[v-u+1];
		return deep[st[len][u]]<deep[st[len][v-(1<<len)+1]]?st[len][u]:st[len][v-(1<<len)+1];
	}
	inline long long getDis(int u,int v){return deep[u]+deep[v]-(deep[getLca(u,v)]<<1);}
	inline void init(){
		for(int u,v,i=1;i<n;i++) u=read(),v=read(),add(u,v,read());
		dfs(1);st[0][1]=id[1];
		for(int i=2;i<=dfscnt;i++) log2[i]=log2[i>>1]+1,st[0][i]=id[i];
		for(int j=1;j<19;j++)for(int i=1;i+(1<<j)<=dfscnt;i++){
			st[j][i]=deep[st[j-1][i]]<deep[st[j-1][i+(1<<(j-1))]]?st[j-1][i]:st[j-1][i+(1<<(j-1))];
		}
	}
}G;

重链剖分

struct Graph{
	int fir[N],nex[M],to[M],tot;
	inline void add(int u,int v,int flag=1){
		to[++tot]=v;
		nex[tot]=fir[u];fir[u]=tot;
		if(flag) add(v,u,0);
	}
	inline void clear(){std::memset(fir,0,sizeof fir);tot=0;}
}G;
int n;
int size[N],deep[N],fa[N];
int son[N],dfscnt,dfn[N],top[N];
void dfs1(int u){
	size[u]=1;
	for(int v,i=G.fir[u];i;i=G.nex[i]){
		v=G.to[i];
		if(v==fa[u]) continue;
		fa[v]=u;deep[v]=deep[u]+1;
		dfs1(v);
		size[u]+=size[v];
		if(size[v]>size[son[u]]) son[u]=v;
	}
}
void dfs2(int u,int topnow=1){
	top[u]=topnow;dfn[u]=++dfscnt;
	if(!son[u]) return;
	dfs2(son[u],topnow);
	for(int i=G.fir[u];i;i=G.nex[i])if(!dfn[G.to[i]]) dfs2(G.to[i],G.to[i]);
}

dinic 最大流

#define Type int
#define _INF _INT_INF
struct Graph{
	int fir[N],_fir[N],nex[M],to[M],tot;
	Type w[M];
	inline void add(int u,int v,Type c,int flag=1){
		to[++tot]=v;nex[tot]=fir[u];fir[u]=tot;w[tot]=c;
		if(flag) add(v,u,0,0);
	}
}G;
int n,S,T;
int deep[N];
int left,right,que[N];
inline int bfs(){
	__builtin_memset(deep,0,(n+1)*sizeof deep[0]);
	left=right=0;que[0]=S;deep[S]=1;
	int u;
	while(left<=right){
		u=que[left++];
		for(int v,i=G.fir[u];i;i=G.nex[i]){
			v=G.to[i];
			if(deep[v]||!G.w[i]) continue;
			deep[v]=deep[u]+1;que[++right]=v;
			if(v==T) return 1;
		}
	}
	return 0;
}
Type dfs(int u,Type now=_INF){
	if(u==T) return now;
	Type res=now;
	for(int v,&i=G._fir[u];i;i=G.nex[i]){
		v=G.to[i];
		if(deep[v]!=deep[u]+1||!G.w[i]) continue;
		Type k=dfs(v,lib::min(res,G.w[i]));
		if(!k) deep[v]=0;
		else G.w[i]-=k,G.w[i^1]+=k,res-=k;
		if(!res) break;
	}
	return now-res;
}
inline Type dinic(){
	Type ans=0;
	while(bfs()){
		Type now;
		__builtin_memcpy(G._fir,G.fir,(n+1)*sizeof G.fir[0]);
		while(now=dfs(S)) ans+=now;
	}
	return ans;
}

最小费用最大流(放错了,本来应该是普通费用流,放成 zkw 了)

int n,S,T;
int mincost,maxflow,h[N];
int vis[N];
inline void spfa(){
	static int que[M*10],left,right;
	__builtin_memset(h,0x3f,sizeof h);
	h[T]=0;vis[T]=1;
	left=0;right=-1;que[++right]=T;
	int u,i,v;
	while(left<=right){
		u=que[left++];vis[u]=0;
		for(i=G.fir[u];i;i=G.nex[i]){
			v=G.to[i];
			if(G.w[i]||h[v]<=h[u]-G.c[i]) continue;
			h[v]=h[u]-G.c[i];
			if(!vis[v]) que[++right]=v,vis[v]=1;
		}
	}
}
int dfs(int u,int want=_INT_INF){
	if(u==T) return mincost+=(h[S]-h[T])*want,maxflow+=want,want;
	vis[u]=1;
	int last=want;
	for(int v,&i=G._fir[u];i;i=G.nex[i]){
		v=G.to[i];
		if(!G.w[i]||vis[v]||G.c[i]!=h[u]-h[v]) continue;
		int k=dfs(v,lib::min(last,G.w[i]));
		G.w[i]-=k;G.w[i^1]+=k;last-=k;
		if(!last) break;
	}
	return want-last;
}
inline int relable(){
	int d=_INT_INF;
	for(int i=_INT_INF;i<=n;i++)if(vis[i])
		for(int j=G.fir[i];j;j=G.nex[j])if(G.w[j]&&!vis[G.to[j]]) lib::chkMin(d,G.c[j]-h[i]+h[G.to[j]]);
	if(d==_INT_INF) return 0;
	for(int i=1;i<=n;i++)if(vis[i]) h[i]+=d;
	return 1;
}
inline void zkw(){
	spfa();
	do{
		do{
			__builtin_memset(vis,0,sizeof vis);__builtin_memcpy(G._fir,G.fir,sizeof G._fir);
		}while(dfs(S));
	}while(relable());
}

zkw 费用流(能带有负权):https://artofproblemsolving.com/community/c1368h1020435

int n,m,S,T;
int mincost,maxflow,h[N];
int vis[N];
inline void spfa(){
	static int que[M*10],left,right;
	__builtin_memset(h,0x3f,sizeof h);
	h[S]=0;vis[S]=1;
	left=0;right=-1;que[++right]=S;
	int u,i,v;
	while(left<=right){
		u=que[left++];vis[u]=0;
		for(i=G.fir[u];i;i=G.nex[i]){
			v=G.to[i];
			if(!G.w[i]||h[v]<=h[u]+G.c[i]) continue;
			h[v]=h[u]+G.c[i];
			if(!vis[v]) que[++right]=v,vis[v]=1;
		}
	}
}
int dfs(int u,int want=_INT_INF){
	if(u==T) return mincost+=(h[S]-h[T])*want,maxflow+=want,want;
	vis[u]=1;
	int last=want;
	for(int v,&i=G._fir[u];i;i=G.nex[i]){
		v=G.to[i];
		if(!G.w[i]||vis[v]||G.c[i]!=h[u]-h[v]) continue;
		int k=dfs(v,lib::min(last,G.w[i]));
		G.w[i]-=k;G.w[i^1]+=k;last-=k;
		if(!last) break;
	}
	return want-last;
}
inline int relable(){
	int d=_INT_INF;
	for(int i=1;i<=n;i++)if(vis[i])
		for(int j=G.fir[i];j;j=G.nex[j])if(G.w[j]&&!vis[G.to[j]]) lib::chkMin(d,G.c[j]-h[i]+h[G.to[j]]);
	if(d==_INT_INF) return 0;
	for(int i=1;i<=n;i++)if(vis[i]) h[i]+=d;
	return 1;
}
inline void zkw(){
	spfa();
	do{
		do{
			__builtin_memset(vis,0,sizeof vis);__builtin_memcpy(G._fir,G.fir,sizeof G._fir);
		}while(dfs(S));
	}while(relable());
}

有源汇上下界最大流

long long d[N];
inline void add(int u,int v,long long l,long long r){
	G.add(u,v,r-l);
	d[u]-=l;d[v]+=l;
}
int main(){
	int s=n+1,t=s+1;
	S=t+1;T=S+1;
	long long sum=0;
	for(int i=1;i<=t;i++){
		if(d[i]>0) G.add(S,i,d[i]),sum+=d[i];
		else if(d[i]<0) G.add(i,T,-d[i]);
	}
	G.add(t,s,LL_INF);
	if(dinic()^sum) puts("-1\n");
	else{
		for(int i=G.fir[S];i;i=G.nex[i]) G.w[i]=G.w[i^1]=0;
		for(int i=G.fir[T];i;i=G.nex[i]) G.w[i]=G.w[i^1]=0;
		sum=G.w[G.tot];G.w[G.tot]=G.w[G.tot-1]=0;
		S=s;T=t;
		printf("%lld\n\n",sum+dinic());
	}
	return 0;
}

最小割树

Graph G,T; 
struct Flow{
	int S,T;
	int deep[N];
	int left,right,que[N];
	inline int bfs(){
		std::memset(deep,0,sizeof deep);
		left=right=0;
		que[0]=S;deep[S]=1;
		int u;
		while(left<=right){
			u=que[left++];
			for(int v,i=G.fir[u];i;i=G.nex[i]){
				v=G.to[i];
				if(deep[v]||!G.w[i]) continue;
				deep[v]=deep[u]+1;que[++right]=v;
				if(v==T) return 1;
			}
		}
		return 0;
	}
	int dfs(int u,int now=INT_INF){
		if(u==T) return now;
		int res=now;
		for(int v,&i=G.fir_[u];i;i=G.nex[i]){
			v=G.to[i];
			if(deep[v]!=deep[u]+1||!G.w[i]) continue;
			int k=dfs(v,std::min(res,G.w[i]));
			if(!k) deep[v]=0;
			else G.w[i]-=k,G.w[i^1]+=k,res-=k;
			if(!res) break;
		}
		return now-res;
	}
	inline void init(){
		for(int i=2;i<=G.tot;i+=2){
			G.w[i]+=G.w[i^1];
			G.w[i^1]=0;
		}
	}
	inline int dinic(int s,int t){
		init();S=s;T=t;
		int ans=0,now=0;
		while(bfs()){
			std::memcpy(G.fir_,G.fir,sizeof G.fir);
			while(now=dfs(s)) ans+=now;
		}
		return ans;
	}
}F;
int min[11][N],fa[11][N],deep[N];
int node[N],tmp1[N],tmp2[N];
void build(int l,int r){
	if(l==r) return;
	int s=node[l],t=node[l+1];
	int cut=F.dinic(s,t);
	T.add(s,t,cut);T.add(t,s,cut);
	int cnt1=0,cnt2=0;
	for(int i=l;i<=r;i++){
		if(F.deep[node[i]]) tmp1[++cnt1]=node[i];
		else tmp2[++cnt2]=node[i];
	}
	for(int i=l;i<l+cnt1;i++) node[i]=tmp1[i-l+1];
	for(int i=l+cnt1;i<=r;i++) node[i]=tmp2[i-cnt1-l+1];
	build(l,l+cnt1-1);build(l+cnt1,r);
}

HLPP 最大流

int S,T;
int left,right,que[N*100];
int in[N];
int h[N],cnth[N*2];
long long res[N];
inline void bfs(){
	std::memset(h,0x3f,sizeof h);h[T]=0;
	left=right=0;que[0]=T;in[T]=1;
	int u;
	while(left<=right){
		u=que[left++];in[u]=0;
		for(int v,i=G.fir[u];i;i=G.nex[i]){
			v=G.to[i];
			if(!G.w[i^1]||h[v]<=h[u]+1) continue;
			h[v]=h[u]+1;
			if(!in[v]) que[++right]=v,in[v]=1;
		}
	}
}
inline int pqueCmp(const int &a,const int &b){return h[a]<h[b];}
std::priority_queue<int,std::vector<int>,int(*)(const int &a,const int &b)>pque(pqueCmp);
inline void push(int u){
	for(int v,i=G.fir[u];i;i=G.nex[i]){
		v=G.to[i];
		if(h[v]+1!=h[u]||!G.w[i]) continue;
		long long k=std::min(G.w[i],res[u]);
		G.w[i]-=k;G.w[i^1]+=k;
		res[u]-=k;res[v]+=k;
		if(!in[v]&&v!=T&&v!=S) in[v]=1,pque.push(v);
		if(!res[u]) break;
	}
}
inline void relabel(int u){
	h[u]=INT_INF;
	for(int v,i=G.fir[u];i;i=G.nex[i]){
		v=G.to[i];
		if(G.w[i]) h[u]=std::min(h[u],h[v]+1);
	}
}
inline long long hlpp(int s,int t){
	S=s;T=t;
	bfs();
	if(h[S]==INT_INF) return 0;
	h[S]=n;
	for(int i=1;i<=n;i++)if(h[i]<INT_INF) cnth[h[i]]++;
	for(int v,i=G.fir[S];i;i=G.nex[i]){
		v=G.to[i];
		if(G.w[i]&&h[v]<INT_INF){
			res[S]-=G.w[i];res[v]+=G.w[i];
			G.w[i^1]+=G.w[i];G.w[i]=0;
			if(!in[v]&&v!=T&&v!=S) pque.push(v),in[v]=1;
		}
	}
	int u;
	while(!pque.empty()){
		u=pque.top();pque.pop();in[u]=0;
		push(u);
		if(res[u]){
			if(!--cnth[h[u]]){
				for(int i=1;i<=n;i++)if(h[i]>h[u]&&i!=S&&i!=T) h[i]=n+1;
			}
			relabel(u);cnth[h[u]]++;
			pque.push(u);in[u]=1;
		}
	}
	return res[T];
}

Stoer-Wagner 求无向图最小割

int S,T;
int w[N],inA[N];
int del[N],dis[N][N];
inline int mincut(int x){
	std::memset(w,0,sizeof w);std::memset(inA,0,sizeof inA);
	w[0]=-1;
	for(int id,i=1;i<=n-x+1;i++){
		id=0;
		for(int j=1;j<=n;j++)if(!inA[j]&&!del[j]&&w[j]>w[id]) id=j;
		inA[id]=1;
		if(i==n-x) S=id;
		else if(i==n-x+1) T=id;
		for(int j=1;j<=n;j++)if(!inA[j]&&!del[j]) w[j]+=dis[id][j];
	}
	return w[T];
}
inline int sw(){
	int ret=1e9;
	for(int i=1;i<n;i++){
		ret=std::min(ret,mincut(i));
		del[T]=1;
		for(int j=1;j<=n;j++) dis[S][j]+=dis[T][j],dis[j][S]+=dis[j][T];
	}
	return ret;
}

tarjan 最小树形图

int uniFa[N];
inline int find(int k){return k==uniFa[k]?k:uniFa[k]=find(uniFa[k]);}
struct Edge{
	int u,v,w,w0;
};
struct Node{
	Node *ls,*rs,*root;
	int deep,tag;
	Edge *edge;
	inline void pushdown(){
		ls->tag+=tag;rs->tag+=tag;
		edge->w+=tag;
		tag=0;
	}
}nullNode,*null=&nullNode;
int tot;
inline void New(Node *&x,Edge *e){
	x=new Node;
	x->deep=1;x->tag=0;
	x->ls=x->rs=null;
	x->root=x;x->edge=e;
}
Node *merge(Node *x,Node *y){
	if(x==null) return y;
	if(y==null) return x;
	if(x->edge->w+x->tag>y->edge->w+y->tag) std::swap(x,y);
	x->pushdown();
	x->rs=merge(x->rs,y);
	if(x->ls->deep<x->rs->deep) std::swap(x->ls,x->rs);
	x->deep=x->rs->deep+1;
	x->ls->root=x->rs->root=x;
	return x;
}
inline void pop(Node *&x){
	x->pushdown();
	Node *ls=x->ls,*rs=x->rs;
	delete x;
	x=merge(ls,rs);
}
int n,m;
int vis[N],fa[N];
int nex[N];
Edge *in[M],edge[M];
Node *p[N];
inline void contraction(){
	for(int i=1;i<=n;i++) p[i]=null,uniFa[i]=i;
	for(int i=1;i<=m;i++){
		Node *tmp;
		New(tmp,&edge[i]);
		p[edge[i].v]=merge(p[edge[i].v],tmp);
	}
	vis[1]=1;
	for(int u=1,pre=1,o;p[u];pre=u,vis[u]=1){
		do{
			in[u]=p[u]->edge;pop(p[u]);
			u=find(in[u]->u);
		}while(u==pre&&p[u]!=null);
		if(u==pre) break;
		if(!vis[u]) continue;
		p[++n]=null;uniFa[n]=n;
		for(pre=u;u^n;){
			uniFa[u]=fa[u]=n;
			if(p[u]!=null) p[u]->tag-=in[u]->w;
			p[n]=merge(p[n],p[u]);
			o=find(in[u]->u);
			nex[o==n?pre:o]=u;
			u=o;
		}
	}
}
int expand(int,int);
int expand(int u){
	int ans=0;
	for(int x=nex[u];x^u;x=nex[x]){
		if(in[x]->w0==INT_INF) return INT_INF;
		if((ans+=in[x]->w0+expand(in[x]->v,x))>=INT_INF) return INT_INF;
	}
	return ans;
}
inline int expand(int u,int goal){
	int ans=0;
	for(;u^goal;u=fa[u])
		if((ans+=expand(u))>=INT_INF) return INT_INF;
	return ans;
}
int main(){
	n=read();m=read();int root=read();
	for(int i=1;i<=m;i++) edge[i].u=read(),edge[i].v=read(),edge[i].w=edge[i].w0=read();
	for(int i=1;i<n;i++) edge[++m]={i,i+1,INT_INF,INT_INF};
	edge[++m]={n,1,INT_INF,INT_INF};
	contraction();
	int ans=expand(root,n);
	printf("%d\n",ans==INT_INF?-1:ans);
	return 0;
}

spfa 找负环

int dis[N],cnt[N];
int left,right,que[N];
inline int spfa(){
	std::memset(dis,0x3f,sizeof dis);std::memset(cnt,0,sizeof cnt);
	right=left=0;que[0]=1;
	dis[1]=0;
	int u,v,i;
	while(left<=right){
		u=que[left++];
		for(i=G.fir[u];i;i=G.nex[i]){
			v=G.to[i];
			if(dis[v]>dis[u]+G.w[i]){
				dis[v]=dis[u]+G.w[i];
				cnt[v]++;
				if(cnt[v]>n) return 1;
				que[++right]=v;
			}
		}
	}
	return 0;
}

支配树

Graph G,H,T;
int uni[N],min[N];
int dfscnt,dfn[N],id[N],fa[N];
int sdom[N],idom[N];
inline int find(int k){
	if(k==uni[k]) return k;
	int ret=find(uni[k]);
	if(dfn[sdom[min[uni[k]]]]<dfn[sdom[min[k]]]) min[k]=min[uni[k]];
	return uni[k]=ret;
}
void dfs(int u){
	dfn[u]=++dfscnt;id[dfscnt]=u;
	for(int i=G.fir[u];i;i=G.nex[i])
		if(!dfn[G.to[i]]) fa[G.to[i]]=u,dfs(G.to[i]);
}
inline void work(int s){
	dfs(s);
	for(int i=1;i<=n;i++) sdom[i]=uni[i]=min[i]=i;
	for(int u,i=dfscnt;i>1;i--){
		u=id[i];
		for(int v,i=H.fir[u];i;i=H.nex[i]){
			v=H.to[i];
			if(!dfn[v]) continue;
			find(v);
			if(dfn[sdom[min[v]]]<dfn[sdom[u]]) sdom[u]=sdom[min[v]];
		}
		uni[u]=fa[u];
		T.add(sdom[u],u);u=fa[u];
		for(int v,i=T.fir[u];i;i=T.nex[i]){
			v=T.to[i];
			find(v);idom[v]=(u==sdom[min[v]])?u:min[v];
		}
		T.fir[u]=0;
	}
	for(int u,i=2;i<=dfscnt;i++){
		u=id[i];
		if(idom[u]^sdom[u]) idom[u]=idom[idom[u]];
	}
}
int ans[N];
inline void get_ans(){
	for(int i=dfscnt;i>1;i--) ans[idom[id[i]]]+=++ans[id[i]];
	ans[id[1]]++;
}

LGV 引理

匈牙利

int match[N],vis[N];
int dfs(int u){
	for(int v,i=G.fir[u];i;i=G.nex[i]){
		v=G.to[i];
		if(vis[v]) continue;
		vis[v]=1;
		if(!match[v]||dfs(match[v])) return match[v]=u,match[u]=v,1;
	}
	return 0;
}

二分图最大权匹配 KM

int num_left,num_right;
int G[N][N];
int vis[N],pre[N],match[N],lw[N],d[N];
int que[N],tail,head;
inline int bfs(int u){
    tail=head=0;que[0]=u;
    pre[u]=0;
    while(tail<=head){
        u=que[tail++];vis[u]=1;
        for(int i=num_left+1;i<=num_right;i++)if(G[u][i]==lw[u]+lw[i]){
            if(vis[i]) continue;
            vis[i]=1;
            if(match[i]) pre[match[i]]=u,que[++head]=match[i];
            else{
                int d=u,e=i,t;
                while(d){
                    t=match[d];
                    match[d]=e;match[e]=d;
                    d=pre[d];e=t; 
                }
                return 1;
            }
        }
    }
    return 0;
}
inline LL max_match(){
    for(int i=1;i<=num_left;i++){
        for(int j=num_left+1;j<=num_right;j++) lw[i]=std::max(lw[i],G[i][j]);
    }
    for(int i=1;i<=num_left;i++){
        std::memset(vis,0,sizeof vis);std::memset(d,0x3f,sizeof d);
        if(bfs(i)) continue;
        for(int j=1;j<=num_left;j++)if(vis[j])
            for(int k=num_left+1;k<=num_right;k++)
                if(!vis[k]) d[k]=std::min(d[k],lw[j]+lw[k]-G[j][k]);
        while(1){
            int now=INT_INF,to,s;
            for(int j=num_left+1;j<=num_right;j++)if(!vis[j]) now=std::min(now,d[j]);
            for(int j=1;j<=num_left;j++)if(vis[j]) lw[j]-=now;
            for(int j=num_left+1;j<=num_right;j++)
                if(vis[j]) lw[j]+=now;
                else d[j]-=now,to=d[j]?to:j;
            if(!match[to]) break;
            s=match[to];vis[to]=vis[s]=1;//打上 vis 标记
            for(int j=num_left+1;j<=num_right;j++)if(!vis[j]) d[j]=std::min(d[j],lw[s]+lw[j]-G[s][j]);
        }
        std::memset(vis,0,sizeof vis);
        bfs(i);
    }
    long long ans=0;
    for(int i=1;i<=num_right;i++) ans+=lw[i];
    return ans; 
}

建虚树

inline void buildVT(int n,int *a,Graph &G){
	std::sort(a+1,a+1+n,[](const int &p,const int &q){return dfn[p]<dfn[q];});
	static int stack[N],top;top=G.tot=0;
	stack[++top]=1;
	for(int lca,i=1+(a[i]==1);i<=n;i++){
		lca=getLca(a[i],stack[top]);
		if(lca^stack[top]){
			while(dfn[lca]<dfn[stakc[top-1]]) G.add(stack[top-1],stack[top]),top--;
			if(lca^stack[top-1]) G.fir[lca]=0,G.add(lca,stack[top]),stack[top]=lca;
			else G.add(lca,stack[top--]);
		}
		G.fir[a[i]]=0;stack[++top]=a[i];
	}
	while(top--) G.add(stack[top],stack[top+1]);
}

树的最小表示法

struct Center{int a,b;};
int size[N],maxson[N];
void getMaxs(int u,int fa,int n,const Graph &G){
	size[u]=1;maxson[u]=0;
	for(int v,i=G.fir[u];i;i=G.nex[i]){
		v=G.to[i];
		if(v==fa) continue;
		getMaxs(v,u,n,G);
		size[u]+=size[v];maxson[u]=std::max(maxson[u],size[v]);
	}
	maxson[u]=std::max(maxson[u],n-size[u]);
}
inline Center getCenter(int n,const Graph &G){
	getMaxs(1,0,n,G);
	int min=1e9;
	for(int i=1;i<=n;i++) min=std::min(maxson[i],min);
	Center ret={0,0};
	for(int i=1;i<=n;i++)if(maxson[i]==min) (ret.a?ret.b:ret.a)=i;
	return ret;
}
int fa[N];
std::vector<int>p[N];
int dfs(int u,int deep,const Graph &G){
	p[deep].push_back(u);
	int ret=deep;
	for(int v,i=G.fir[u];i;i=G.nex[i]){
		v=G.to[i];
		if(v==fa[u]) continue;
		fa[v]=u;
		ret=std::max(ret,dfs(v,deep+1,G));
	}
	return ret;
}
int tag[N];
std::vector<int>sonTag[N];
inline void getans(int u,int *ans,const Graph &G){
	ans[++ans[0]]=0;
	std::vector<int>v;
	for(int i=G.fir[u];i;i=G.nex[i])if(G.to[i]^fa[u]) v.push_back(G.to[i]);
	std::sort(v.begin(),v.end(),[](const int &a,const int &b){return tag[a]<tag[b];});
	for(int j=0,sz=v.size();j<sz;j++) getans(v[j],ans,G);
	ans[++ans[0]]=1;
}
inline int ahu(int n,const Graph &G,int root,int *ans){
	for(int i=1;i<=n;i++) p[i].clear(),sonTag[i].clear();
	fa[root]=0;int h=dfs(root,1,G);
	for(int j=0,sz=p[h].size();j<sz;j++) tag[p[h][j]]=0;
	int tot=0;
	for(int i=h-1;i;i--){
		for(int j=0,sz=p[i+1].size(),v;j<sz;j++){
			v=p[i+1][j];
			sonTag[fa[v]].push_back(tag[v]);
		}
		std::sort(p[i].begin(),p[i].end(),[](const int &a,const int &b){return sonTag[a]<sonTag[b];});
		for(int j=0,sz=p[i].size(),u;j<sz;j++){
			u=p[i][j];
			if(j&&sonTag[u]!=sonTag[p[i][j-1]]) tot++;
			tag[u]=tot;
		}
	}
	getans(root,ans,G);
	return h;
}

点分治

int root,sum;
void find(int x,int fa=0){
	size[x]=1;max[x]=0;
	for(int v,i=G.fir[x];i;i=G.nex[i]){
		v=G.to[i];
		if(v==fa||vis[v]) continue;
		find(v,x);
		size[x]+=size[v];
		if(max[x]<size[v]) max[x]=size[v];
	}
	if(max[x]<sum-size[x]) max[x]=n-size[x];
	if(max[x]<max[root]) root=x;
}
inline void calc(int u){
	
}
void divide(int u){
	vis[u]=1;
	calc(u);
	for(int v,i=G.fir[u];i;i=G.nex[i]){
		v=G.to[i];
		if(vis[v]) continue;
		root=0;sum=size[v];
		find(v);find(root);
		divide(root);
	}
}
int main(){
	max[0]=INT_INF;sum=n;
	find(1);find(root);
	divide(root);
	return 0;
}
posted @ 2022-03-09 21:27  suxxsfe  阅读(69)  评论(0编辑  收藏  举报