LOJ#2718 & 洛谷P4768 [NOI2018] 归程 Kruskal重构树+Dijkstra

题目链接:
LOJ2718
洛谷P4768

k r u s k a l kruskal kruskal重构树不会的话珂以看这篇题解qwq
这道题考虑把边按照海拔从大到小排序,让重构的树成为一棵以海拔为关键字的小根堆。
重构树的每个节点记录两个信息 v a l , d i s val,dis val,dis,分别表示当前节点子树内最小的海拔和最小到 1 1 1的距离,其中叶子节点(即原图的节点) v a l = 0 val=0 val=0
对于每个询问给出的水位 p p p,假设重构树上有一个节点 u u u使得 v a l [ u ] &gt; = p val[u]&gt;=p val[u]>=p v a l [ f a ] &lt; = p val[fa]&lt;=p val[fa]<=p,说明当且仅当 x , y x,y x,y u u u的子树内时, x x x能开车到达 y y y y y y也能开车到达 x x x
所以此时答案为 d i s [ u ] dis[u] dis[u](即 u u u的子树内的节点到 1 1 1的距离的最小值)
原图中节点的 d i s dis dis珂以一遍 d i j k s t r a dijkstra dijkstra求出来,非叶子节点的 d i s dis dis v a l val val珂以 d f s dfs dfs一遍qwq。
时间复杂度: O ( ( n + m + q ) l o g n ) O((n+m+q)logn) O((n+m+q)logn) d i j k s t r a dijkstra dijkstra O ( ( n + m ) l o g n ) O((n+m)logn) O((n+m)logn),询问 O ( q l o g n ) O(qlogn) O(qlogn)

代码

注: l o j loj loj上记得加 f r e o p e n freopen freopen qwq

#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#include<vector>
#include<queue>
#define re register int
#define rl register ll
using namespace std;
typedef long long ll;
int read() {
	re x=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9') {
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9') {
		x=10*x+ch-'0';
		ch=getchar();
	}
	return x*f;
}
inline void write(int x) {
	if(x>9)	write(x/10);
	putchar(x%10+'0');
}
namespace I_Love {

const int Size=400005;
int n,m,q,k,s,cnt,head[Size];
struct Edge {
	int u,v,h,t,next;
	//h:海拔   t:长度 
} w[Size<<1],tree[Size<<1];
void AddEdge(int u,int v,int h,int t) {
	w[++cnt].u=u;
	w[cnt].v=v;
	w[cnt].h=h;
	w[cnt].t=t;
	w[cnt].next=head[u];
	head[u]=cnt;
}
void AddTree(int u,int v) {
	tree[++cnt].v=v;
	tree[cnt].next=head[u];
	head[u]=cnt;
}
struct node {
	int id,dis;
	inline node(int x,int y) {
		id=x,dis=y;
	}
	inline bool operator < (const node b) const {
		return dis>b.dis;
	}
};
priority_queue<node> Q;
int dis[Size];
void Dijkstra(int s) {
	memset(dis,0x3f,sizeof(dis));
	dis[s]=0;
	Q.push(node(s,0));
	while(!Q.empty()) {
		node now=Q.top(); Q.pop();
		int x=now.id,d=now.dis;
		if(d!=dis[x])	continue;
		for(re i=head[x]; i; i=w[i].next) {
			int nxt=w[i].v;
			if(dis[x]+w[i].t<dis[nxt]) {
				dis[nxt]=dis[x]+w[i].t;
				Q.push(node(nxt,dis[nxt]));
			}
		}
	}
}
int father[Size],val[Size];
int Find(int x) {
	if(x==father[x])	return x;
	return father[x]=Find(father[x]);
}
inline bool comp(Edge jzm,Edge xjp) {
	return jzm.h>xjp.h;
}
void Kruskal() {
	sort(w+1,w+1+cnt,comp);
	int maxn=n<<1,all=cnt,tot=n;
	for(re i=1; i<=maxn; i++)	father[i]=i;
	memset(head,0,sizeof(head)); cnt=0;
	for(re i=1; i<=all; i++) {
		int fu=Find(w[i].u);
		int fv=Find(w[i].v);
		if(fu!=fv) {
			father[fu]=father[fv]=++tot;
			AddTree(tot,fu);
			AddTree(tot,fv);
			val[tot]=w[i].h;
			if(tot+1==maxn)	return;
		}
	}
}
int deep[Size],anc[Size][21];
void dfs(int x,int fa) {
	deep[x]=deep[fa]+1;
	anc[x][0]=fa;
	for(re i=1; i<=18; i++) {
		anc[x][i]=anc[anc[x][i-1]][i-1];
	}
	for(int i=head[x]; i; i=tree[i].next) {
		int nxt=tree[i].v;
		if(nxt!=fa) {
			dfs(nxt,x);
			if(dis[nxt]<dis[x]) {
				dis[x]=dis[nxt];
			}
		}
	}
}
int Query(int x,int p) {
	for(re i=18; i>=0; i--) {
		if(deep[anc[x][i]]>=0 && val[anc[x][i]]>p) {
			x=anc[x][i];
		}
	}
	return dis[x];
}
void Fujibayashi_Ryou() {
	int T=read();
	while(T--) {
		memset(head,0,sizeof(head)); cnt=0;
		n=read();
		m=read();
		for(re i=1; i<=m; i++) {
			int u=read();
			int v=read();
			int t=read();
			int h=read();
			AddEdge(u,v,h,t);
			AddEdge(v,u,h,t);
		}
		q=read();
		k=read();
		s=read();
		Dijkstra(1);
		Kruskal();
		dfs((n<<1)-1,0);
		int lastans=0;
		while(q--) {
			int v=(read()+k*lastans-1)%n+1;
			int p=(read()+k*lastans)%(s+1);
			printf("%d\n",lastans=Query(v,p));
		}
	}
}

}
int main() {
	I_Love::Fujibayashi_Ryou();
	return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值