牛客练习赛88 D都市的柏油路太硬
Posted goto_1600
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了牛客练习赛88 D都市的柏油路太硬相关的知识,希望对你有一定的参考价值。
题意:
给定一个图,每两个点之间的距离是他们所有路径中最大值的最小值,求这样的图的最小生成树。有q次询问,求该生成树的a,b之间的最大值。n<=1e5 m<=5e5 q<=1e7
思路:
是一颗克鲁斯卡尔重构树,求lca,倍增过不去,要么就树剖要么就欧拉序,这里讲一下欧拉序,欧拉序就是遍历一次把他该点存进遍历序列里,dfs遍历的伪代码大概是这样
void dfs(int u,int fa){
id[++cnt]=u;
in[u]=cnt;
dep[u]=dep[fa]+1;
for(auto j:v[u]){
dfs(j,u);
id[++cnt]=u;
}
图大概长这样
可以发现,任意两点,他们的lca就是他们欧拉序列中深度最小的点,然后st表求深度最小值的id就可以了。
惊奇的发现,树剖的复杂度和静态st表的速度,在q等于1E7的时候竟然差不多,可能是随机的性质,也可能是树剖太优秀了 。logn的算法吊打o(1)算法(bushi)
// Problem: 都市的柏油路太硬
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/11178/D
// Memory Limit: 1048576 MB
// Time Limit: 6000 ms
//
// Powered by CP Editor (https://cpeditor.org)
//#pragma GCC target("avx")
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
//#pragma GCC optimize("Ofast")
// created by myq
#include<iostream>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<cmath>
#include<cctype>
#include<stack>
#include<queue>
#include<list>
#include<vector>
#include<set>
#include<map>
#include<sstream>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
#define x first
#define y second
typedef pair<int,int> pii;
const int mod=998244353;
typedef unsigned long long ull;
inline ull myRand(ull &k1, ull &k2){
ull k3 = k1, k4 = k2;
k1 = k4;
k3 ^= (k3 <<23);
k2 = k3 ^ k4 ^ (k3 >>17) ^ (k4 >>26);
return k2 + k4;
}
inline pair<int,int>myRanq(ull&k1,ull&k2,int MAXN){
int x=myRand(k1,k2)%MAXN+1,y=myRand(k1,k2)%MAXN+1;
if(x>y)return make_pair(y,x);
else return make_pair(x,y);
}
const int N=300010;
int p[N];
vector<int>v[N];
int dep[N];
int id[N];
int idx;
int in[N];
int out[N];
int Lg[N];
int val[N];
int st[N][20];
int cnt;
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
struct edge{
int a;
int b;
int c;
bool operator<(const edge&w)const
{
return c<w.c;
}
}e[500010];
int cmp(int a,int b){
if(dep[a]<dep[b]) return a;
else return b;
}
void init_st(){
for(int i=1;i<=cnt;i++) Lg[i]=(int)log2(i);
for(int i=1;i<=cnt;i++) st[i][0]=id[i];
for(int i=1;i<=19;i++)
{
for(int j=1;j+(1<<i)-1<=cnt;j++){
st[j][i]=cmp(st[j][i-1],st[j+(1<<i-1)][i-1]);
}
}
}
void dfs(int u,int fa){
id[++cnt]=u;
in[u]=cnt;
dep[u]=dep[fa]+1;
for(auto j:v[u]){
dfs(j,u);
id[++cnt]=u;
}
}
int get_lca(int l,int r){
if(in[r]<in[l])
swap(l,r);
// cout<<l<<" "<<r<<endl;
int len=Lg[in[r]-in[l]+1];
// cout<<len<<endl;
return cmp(st[in[l]][len],st[in[r]-(1<<len)+1][len]);
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=2*n-1;i++) p[i]=i;
int idx=n+1;
for(int i=0;i<m;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
e[i]={a,b,c};
}
sort(e,e+m);
for(int i=0;i<m;i++)
{
int a=e[i].a,b=e[i].b;
int c=e[i].c;
a=find(a);
b=find(b);
if(a!=b)
{
v[idx].push_back(a);
v[idx].push_back(b);
val[idx]=c;
p[a]=idx;
p[b]=idx;
idx++;
}
}
int root=2*n-1;
dfs(root,0);
init_st();
int q;
scanf("%d",&q);
ull a,b;
scanf("%llu%llu",&a,&b);
int x;
int y;
pii P;
int dd;
int ans=0;
while(q--)
{
P=myRanq(a,b,n);
x=P.x;
y=P.y;
dd=get_lca(x,y);
// cout<<x<<" "<<y<<" "<<dd<<endl;
ans^=val[dd];
}
cout<<ans<<endl;
return 0;
}
/**
* In every life we have some trouble
* When you worry you make it double
* Don't worry,be happy.
**/
以上是关于牛客练习赛88 D都市的柏油路太硬的主要内容,如果未能解决你的问题,请参考以下文章