最短路树学习笔记及例题

定义构建一棵树,使得任意不属于根的节点x,dis(root,x)=原图走到x的最短路。

构建方法:就是在跑dijkstra时同时维护每个点是哪个点哪条边更新的,这个点这条边就是它在最短路树上的父亲/到父亲的边

例题:

T1.bzoj3694 最短路

题意:给定了最短路树要求不经过树上到i点最后一条边的到i点最短路。

显然到一个点走法一定是经过一条非树边到达的,那么考虑每一条非树边会产生怎样的贡献:假设一条非树边(u,v)权值w,那么可以发现对于任意u,v路径上除lca外的点x,假设x在u到lca上,它的ans可以用dis(v)+w+dis(u)-dis(x)来更新,带x的项最后考虑那么就是链取min显然大力树剖即可。

#include
#define ll long long
using namespace std;
const int N=2e5+100;
const ll inf=1e18;

template
void rd(T &x)
{
	char c=getchar();x=0;bool f=0;
	while(!isdigit(c))f|=(c=='-'),c=getchar();
	while(isdigit(c))x=x*10+c-48,c=getchar();
	if(f)x=-x;
}
void Mn(ll &x,ll y)
{x=min(x,y);}

int bg[N],ed[N],val[N],num=0;
int n,m,hd[N],to[N],w[N],nxt[N],tot=-1;
int fa[N],son[N],dfn[N],top[N],dep[N],sz[N],tim=0;
ll dis[N],seg[N<<2],laz[N<<2];

void add(int x,int y,int z)
{
	nxt[++tot]=hd[x],to[tot]=y,w[tot]=z,hd[x]=tot;
	nxt[++tot]=hd[y],to[tot]=x,w[tot]=z,hd[y]=tot;
}

void dfs0(int x,int f)
{
	fa[x]=f,sz[x]=1,son[x]=0;
	for(int i=hd[x],v;~i;i=nxt[i])
	{
		v=to[i];
		if(v==f)continue;
		dep[v]=dep[x]+1,dis[v]=dis[x]+w[i],dfs0(v,x),sz[x]+=sz[v];
		if(sz[v]>sz[son[x]])son[x]=v;
	}
}

void dfs1(int x,int tp)
{
	dfn[x]=++tim,top[x]=tp;
	if(son[x])
	{
		dfs1(son[x],tp);
		for(int i=hd[x],v;~i;i=nxt[i])
		{
			v=to[i];
			if(v==fa[x]||v==son[x])continue;
			dfs1(v,v);
		}
	}
}

int get_lca(int x,int y)
{
	int fx=top[x],fy=top[y];
	while(fx!=fy)
	{
		if(dep[fx]>1;
	push_down(k);
	if(L<=mid)upd(L,R,l,mid,k<<1,x);
	if(R>mid)upd(L,R,mid+1,r,k<<1|1,x);
}

void cg(int x,int y,ll z)
{
	int fx=top[x],fy=top[y];
	//cerr<>1;
	push_down(k);
	if(to<=mid)return qry(to,l,mid,k<<1);
	else return qry(to,mid+1,r,k<<1|1);
}

int main()
{
	int x,y,z,op;
	rd(n),rd(m);
	memset(hd,-1,sizeof hd);
	for(int i=1;i<=m;i++)
	{
		rd(x),rd(y),rd(z),rd(op);
		if(op==1)add(x,y,z);
		else bg[++num]=x,ed[num]=y,val[num]=z;
	}
	dep[1]=1,dfs0(1,0),dfs1(1,1);
	memset(seg,63,sizeof seg);
	memset(laz,63,sizeof laz);
	for(int i=1,u,v,lca;i<=num;i++)
	{
		u=bg[i],v=ed[i];
		if(dep[u]=inf)printf("-1 ");
		else printf("%lld ",res-dis[i]);
	}
}

T2.cf 1005F

求建最短路树的方案

并不用真的把最短路树建出来,因为边权都是1所以很好做,bfs求出每个点的dis,再对每个点遍历所有连到的点,如果dis是当前减一那么必然可以成为当前点前驱,扔进一个vector,那么总方案就是所有点vector size的乘积,输出方案则dfs一下即可。

#include
#define pii pair
#define fi first
#define sc second
#define ll long long
using namespace std;
const int N=2e5+100;
const ll inf=1e18;

template
void rd(T &x)
{
	char c=getchar();x=0;bool f=0;
	while(!isdigit(c))f|=(c=='-'),c=getchar();
	while(isdigit(c))x=x*10+c-48,c=getchar();
	if(f)x=-x;
}
void Mn(ll &x,ll y)
{x=min(x,y);}

int n,m,k,dis[N],can;
bool vis[N];
vectormp[N],fr[N];

void P()
{
	for(int i=1;i<=m;i++)
		vis[i]?putchar('1'):putchar('0');
	puts("");
}

void dfs(int x)
{
	if(x>n)
	{
		P();
		--can;
		if(can==0)exit(0);
	}
	for(int i=0,v,wh;iq;
	memset(dis,-1,sizeof dis);
	dis[1]=0,q.push(1);
	while(!q.empty())
	{
		nw=q.front(),q.pop();
		for(int i=0,v;i

T3.cf 1076D. Edge Deletion

显然就是从最短路树底层往上一个个删除。

#include
#define pii pair
#define fi first
#define sc second
#define ll long long
using namespace std;
const int N=3e5+100;
const ll inf=1e18;

template
void rd(T &x)
{
	char c=getchar();x=0;bool f=0;
	while(!isdigit(c))f|=(c=='-'),c=getchar();
	while(isdigit(c))x=x*10+c-48,c=getchar();
	if(f)x=-x;
}
void Mn(ll &x,ll y)
{x=min(x,y);}

int n,m,k,hd[N],nxt[N*2],to[N*2],cost[N*2],idx[N*2],bf[N],tax[N],tot=-1;
ll dis[N];
bool kep[N];

void add(int x,int y,int z,int id)
{
	nxt[++tot]=hd[x],idx[tot]=id,to[tot]=y,cost[tot]=z,hd[x]=tot;
	nxt[++tot]=hd[y],idx[tot]=id,to[tot]=x,cost[tot]=z,hd[y]=tot;
}

void dij()
{
	priority_queue,greater >pq;
	int nw;ll d;
	memset(dis,63,sizeof dis);
	dis[1]=0,pq.push(pii(0,1));
	while(!pq.empty())
	{
		nw=pq.top().sc,d=pq.top().fi,pq.pop();
		if(dis[nw]d+cost[i])
			{
				dis[v]=d+cost[i];
				bf[v]=idx[i];
				pq.push(pii(dis[v],v));
			}
		}
	}
}

bool cmp(int x,int y)
{return dis[x]>dis[y];}

int main()
{
	rd(n),rd(m),rd(k);
	memset(hd,-1,sizeof hd);
	for(int i=1,u,v,w;i<=m;i++)
	{
		//cerr<k)
	{
		kep[bf[tax[ps++]]]=0;
		--has;
	}
	printf("%d\n",has);
	for(int i=1;i<=m;i++)
		if(kep[i])printf("%d ",i);
}

 

你可能感兴趣的:(不常用但有时很有用的东西,笔记,刷题集,训练集)