2020牛客NOIP赛前集训提高组#3-B-牛半仙的妹子图(最小生成树)

本文介绍了2020年牛客NOIP赛前集训中关于最小生成树的问题,具体讨论了如何解决寻找从特定节点到达其他节点最大困难程度最小值的题目。通过构建最小生成树,利用DFS策略更新每个节点的最大值,并以此计算不同类型的妹子被访问的最小困难程度。特别提示,代码实现时要注意无限大值的设置,建议使用long long类型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

在这里插入图片描述

样例

input:
6 6 3 3 1
1000007
1 1 1 2 2 3
1 6 1
1 2 5
2 3 4
3 6 3
3 4 6
5 6 2
0 2
5 6
9 11
output:
5
8
7

分析

可以先跑最小生成树,求出这个图中从xxx到达任意一个节点所需要的最大困难程度的最小值。
此时有一个很好的思路:
用一个t[i]t[i]t[i]表示种类iii妹子被半仙访问所需要的最少困难程度。最后算的时候枚举妹子的种类,然后判断一下t[i]t[i]t[i]l,rl,rl,r的大小关系就可以快速加进答案里了。

问题是,怎么搞t[i]t[i]t[i]呢???很简单,只要dfsdfsdfs跑一次,记下从xxx到其他节点路上的最大值然后与原来记录的类型iiit[i]t[i]t[i]比较一下记一下最小值就可以了。

代码

#include<bits/stdc++.h>
#define ll long long
#define inf 1<<30//注意1<<29小于1e9,调了半天
using namespace std;
const int MAXN=5e5+10;
struct node{
	int to,w;
	node(){}
	node(int _to,int _w){
		to=_to;w=_w;
	}
};
vector<node> vec[MAXN];
struct edge{int u,v,w;}e[MAXN];
int fa[MAXN],c[MAXN],t[MAXN];
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
bool cmp(edge a,edge b){return a.w<b.w;}
void add(int u,int v,int w){
	vec[u].push_back(node(v,w));
	vec[v].push_back(node(u,w));
}
void dfs(int x,int maxn,int f){
	t[c[x]]=min(t[c[x]],maxn);//与原来的t[i]比较,c[i]是i妹子的种类
	for(int i=0;i<vec[x].size();i++)
		if(vec[x][i].to!=f)
			dfs(vec[x][i].to,max(maxn,vec[x][i].w),x);
}
int main()
{
	int n,m,q,x,opt,mod;ll l,r;
	scanf("%d%d%d%d%d",&n,&m,&q,&x,&opt);
	if(opt) scanf("%d",&mod);int lmt=0;
	for(int i=1;i<=n;i++) scanf("%d",&c[i]),lmt=max(lmt,c[i]);
	for(int i=1,u,v,w;i<=m;i++)
		scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
	for(int i=1;i<=n;i++) fa[i]=i;
	for(int i=1;i<=lmt;i++) t[i]=inf;
	sort(e+1,e+1+m,cmp);
	for(int i=1,u,v,w;i<=m;i++){
		u=e[i].u;v=e[i].v;w=e[i].w;
		if(find(u)!=find(v)) fa[fa[u]]=fa[v],add(u,v,w);//kruskal求最小生成树
	}dfs(x,0,0);ll ans=0;
	while(q--){
		scanf("%lld%lld",&l,&r);
		if(opt) l=(l^ans)%(ll)mod+1,r=(r^ans)%(ll)mod+1;//强制在线烦死了
		if(l>r) swap(l,r);ans=0;
		for(int i=1;i<=lmt;i++)
			if(t[i]<=l) ans+=(ll)(r-l+1);
			//如果所需的t[i]小于区间的下界,那么对于这个种类,无论忍受程度是(l,r)间的哪一个都是可以+1
			//所以在ans中加r-l+1
			else if(t[i]<=r) ans+=(ll)(r-t[i]+1);
			//否则就只能加能加的部分
		printf("%lld\n",ans);
	}
}

END

  • 注意inf的设置,一定一定要小心,尽量开ll。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值