嘗試

Wiz_HUA發表於2024-04-23

1. 裸板子

題目連結:P3379 【模板】最近公共祖先(LCA)

展開程式碼
#include<bits/stdc++.h>
using namespace std;
#define P(x) cout<<#x<<":"<<x<<endl;
#define pb push_back
const int MAXN=int(5e5+5);
int n,m,s;
int lg[MAXN];
int fa[MAXN][22],dep[MAXN];
vector<int> G[MAXN];
void Init_lg() {
	for(int i=1;i<=n;i++)
		lg[i]=lg[i-1]+(1<<lg[i-1]==i);
}
void Dfs0(int u,int p) {
	dep[u]=dep[p]+1;
	fa[u][0]=p;
	for(int i=1;(1<<i)<=dep[u];i++)
		fa[u][i]=fa[fa[u][i-1]][i-1];
	for(auto v:G[u])
		if(v!=p)
			Dfs0(v,u);
}
int lca(int u,int v) {
	if(dep[u]<dep[v])
		swap(u,v);
	while(dep[u]>dep[v])
		u=fa[u][lg[dep[u]-dep[v]]-1];
	if(u==v)
		return u;
	for(int k=lg[dep[u]];k>=0;k--)
		if(fa[u][k]!=fa[v][k])
			u=fa[u][k],v=fa[v][k];
	return fa[u][0];
}
int main()
{
	scanf("%d%d%d",&n,&m,&s);
	for(int i=1;i<n;i++) {
		int u,v;
		scanf("%d%d",&u,&v);
		G[u].pb(v),G[v].pb(u);
	}
	Init_lg();
	Dfs0(s,0);
	for(int i=1;i<=m;i++) {
		int u,v;
		scanf("%d%d",&u,&v);
		printf("%d\n",lca(u,v));
	}
}

2. 提要

2.1 LCA的副產品

  • 常見的做法,在處理LCA的同時維護路徑上的其他資訊(如路徑最大值、路徑最小值、路徑元素個數等可合併的資訊
  • d(u,v)即是二者到LCA的距離和(dep[u]-dep[lca])+(dep[v]-dep[lca])

2.2

3. 應用

3.1 維護路徑最小值

題目連結:P9235 [藍橋杯 2023 省 A] 網路穩定性

最大生成樹優先選擇長邊,使路徑上的最小值最大

展開程式碼
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define fi first
#define sd second
typedef long long ll;
typedef pair<int,int> PII;
const int MAXN=int(3e5+5);
int n,m,q;
int fa[MAXN];
vector<PII> G[MAXN];
struct edge {
	int u,v,w;
}e[MAXN];
int lg[MAXN],dep[MAXN];
int p[MAXN][30],upm[MAXN][30];
int find(int x) {
	return x==fa[x]?x:fa[x]=find(fa[x]);
}
bool cmp(edge a,edge b) {
	return a.w>b.w;
}
void Kruscal() {
	for(int i=1;i<=n;i++)
		fa[i]=i;
	sort(e+1,e+m+1,cmp);
	for(int i=1;i<=m;i++) {
		int u=e[i].u,v=e[i].v,w=e[i].w;
		int fu=find(u),fv=find(v);
		if(fu==fv) continue;
		fa[fu]=fv;
		G[u].pb({v,w});
		G[v].pb({u,w});
	}
}
void Dfs0(int u,int pre,int w_down) {
	dep[u]=dep[pre]+1;
	p[u][0]=pre;
	upm[u][0]=w_down;
	for(int i=1;(1<<i)<=dep[u];i++) {
		p[u][i]=p[p[u][i-1]][i-1];
		upm[u][i]=min(upm[u][i-1],upm[p[u][i-1]][i-1]);
	}
	for(auto t:G[u]) {
		int v=t.fi,w=t.sd;
		if(v!=pre)
			Dfs0(v,u,w);
	}
}
void Init_lca() {
	for(int i=1;i<=n;i++)
		lg[i]=lg[i-1]+(1<<lg[i-1]==i);
	memset(upm,0x3f,sizeof(upm));
	for(int i=1;i<=n;i++)
		if(find(i)==i)
			Dfs0(i,0,0x3f3f3f3f);
}
int Query(int u,int v) {
	if(find(u)!=find(v))
		return -1;
	if(dep[u]<dep[v]) swap(u,v);
	int res=0x3f3f3f3f;
	while(dep[u]>dep[v]) {
		int d=dep[u]-dep[v];
		res=min(res,upm[u][lg[d]-1]);
		u=p[u][lg[d]-1];
	}
	if(u==v)
		return res;
	for(int k=lg[dep[u]];k>=0;k--)
		if(p[u][k]!=p[v][k]) {
			res=min(upm[u][k],res);
			res=min(upm[v][k],res);
			u=p[u][k],v=p[v][k];
		}
	res=min(upm[u][0],res);
	res=min(upm[v][0],res);
	return res;
}
int main()
{
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=m;i++) {
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		e[i]={u,v,w};
	}
	Kruscal();
	Init_lca();
	for(int i=1;i<=q;i++) {
		int u,v;
		scanf("%d%d",&u,&v);
		printf("%d\n",Query(u,v));
	}
}

3.2 維護路徑元素

題目連結:Pxxxx [藍橋杯 2024 省 A] G(未出)

路徑節點顏色總數小 ( $C<=20$ ) ,狀壓維護

展開程式碼
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
#define pb push_back
#define lowbit(x) (x&-x)
const int MAXN=int(1e5+5);
const int MAXC=int(25);
int n,m;
int col[MAXN];
int lg[MAXN],fa[MAXN][30],C[MAXN][30];
int dep[MAXN];
vector<int> G[MAXN];
void dfs(int u,int p) {
	dep[u]=dep[p]+1;
	fa[u][0]=p;
	C[u][0]=(1<<col[u]);
	if(p!=0)
		C[u][0]|=(1<<col[p]);
	for(int i=1;(1<<i)<=dep[u];i++) {
		fa[u][i]=fa[fa[u][i-1]][i-1];
		C[u][i]=C[u][i-1]|C[fa[u][i-1]][i-1];
	}
	for(auto v:G[u])
		if(v!=p)
			dfs(v,u);
}
void init() {
	for(int i=1;i<=n;i++)
		lg[i]=lg[i-1]+(1<<lg[i-1]==i);
	dfs(1,0);
}
int count(int x) {
	int res=0;
	while(x) {
		res++;
		x-=lowbit(x);
	}
	return res;
}
int query(int u,int v) {
	if(u==v)
		return col[u];
	if(dep[u]<dep[v])
		swap(u,v);
	int cols=0;
	while(dep[u]>dep[v]) {
		int t=lg[dep[u]-dep[v]]-1;
		cols|=C[u][t];
		u=fa[u][t];
	}
	if(u==v)
		return count(cols);
	for(int i=lg[dep[u]];i>=0;i--)
		if(fa[u][i]!=fa[v][i]) {
			cols|=(C[u][i]|C[v][i]);
			u=fa[u][i],v=fa[v][i];
		}
	cols|=C[u][0]|C[v][0];
	return count(cols);
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",&col[i]);
	for(int i=1;i<=n-1;i++) {
		int u,v;
		scanf("%d%d",&u,&v);
		G[u].pb(v);
		G[v].pb(u);
	}
	init();
	while(m--) {
		int u,v;
		scanf("%d%d",&u,&v);
		printf("%d\n",query(u,v));
	}
}

3.3

相關文章