[CodeChef Trips]Children Trips
Posted Tan_tan_tann
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CodeChef Trips]Children Trips相关的知识,希望对你有一定的参考价值。
Children Trips
题解
关于这种跳跃的**题,当它 P P P值很大时几次就可以跳到目标节点了,而较小时却会跳很久,所以我们很快就可以想到对询问分类处理。
对于
P
>
n
P>\\sqrt{n}
P>n的询问,它跳到终点的次数大概是
n
\\sqrt{n}
n级别的,我们可以直接用它暴力跳,用倍增维护它下一个可以跳到的节点。
很明显,这样单次询问的时间复杂度是
O
(
n
l
o
g
n
)
O\\left(\\sqrt{n}log\\,n\\right)
O(nlogn)。
而对于
P
⩽
n
P\\leqslant \\sqrt{n}
P⩽n询问,因为这样的
P
P
P的数量很小,我们不妨考虑预处理出这些
P
P
P的倍增数组,即它跳
2
k
2^k
2k步可以跳到哪里,询问时就直接倍增找答案。
很明显,这样的预处理时间复杂度是
O
(
n
n
l
o
g
n
)
O\\left(n\\sqrt{n}log\\,n\\right)
O(nnlogn)的,单次询问时间复杂度为
O
(
l
o
g
n
)
O\\left(log\\,n\\right)
O(logn)。
虽然对于第二类的询问我们只能从两端开始跳,而从上往下跳与从下往上跳两种方法的到的答案不一定相同,但由于它的边权最大是
2
2
2,所以我们整个过程中浪费也只会浪费
1
1
1的跳跃。
可以发现,这并不影响我们得到正确答案。
时间复杂度很明显是 O ( ( n + q ) n l o g n ) O\\left((n+q)\\sqrt{n}log\\,n\\right) O((n+q)nlogn)。
源码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
#define MAXN 100005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long LL;
typedef unsigned long long uLL;
const LL INF=1000000000000000000LL;
const int mo=1e9+7;
const int n1=300;
const int inv2=499122177;
const int jzm=2333;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-7;
typedef pair<int,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1LL)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1LL;}return t;}
int n,m,head[MAXN],tot,dep[MAXN],dis[MAXN],f[MAXN][20],fw[MAXN][20];
int ord[MAXN],idx,totmin,totmax,ans[MAXN];
struct edge{int to,nxt,paid;}e[MAXN<<1];
struct ming{int u,v,p,id;}smin[MAXN],smax[MAXN];
vector<int>vec[305];
void addEdge(int u,int v,int w){e[++tot]=(edge){v,head[u],w};head[u]=tot;}
void dosaka(int u,int fa){
dep[u]=dep[fa]+1;f[u][0]=fa;ord[++idx]=u;
for(int i=1;i<=18;i++)f[u][i]=f[f[u][i-1]][i-1];
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;if(v==fa)continue;
dis[v]=dis[u]+e[i].paid;dosaka(v,u);
}
}
int lca(int a,int b){
if(dep[a]>dep[b])swap(a,b);
for(int i=18;i>=0;i--)if(dep[f[b][i]]>=dep[a])b=f[b][i];
if(a==b)return a;
for(int i=18;i>=0;i--)if(f[a][i]!=f[b][i])a=f[a][i],b=f[b][i];
return f[a][0];
}
signed main(){
read(n);
for(int i=1;i<n;i++){
int u,v,w;read(u);read(v);read(w);
addEdge(u,v,w);addEdge(v,u,w);
}
dosaka(1,0);read(m);
for(int i=1;i<=m;i++){
int s,f,p;read(s);read(f);read(p);
if(p<=n1)smin[++totmin]=(ming){s,f,p,i};
else smax[++totmax]=(ming){s,f,p,i};
}
for(int i=1;i<=totmin;i++)vec[smin[i].p].push_back(i);
for(int i=2;i<=n1;i++){
if(vec[i].empty())continue;
for(int j=1;j<=n;j++){
int x=ord[j],now=x;
for(int k=18;k>=0;k--)
if(dis[x]-dis[f[now][k]]<=i)now=f[now][k];
fw[x][0]=now;
for(int k=1;k<=18;k++)fw[x][k]=fw[fw[x][k-1]][k-1];
}
for(int j=0;j<vec[i].size();j++){
int t=vec[i][j],u=smin[t].u,v=smin[t].v,u_v=lca(u,v),x=v;
for(int k=18;k>=0;k--)if(dep[fw[u][k]]>dep[u_v])
u=fw[u][k],ans[smin[t].id]+=(1<<k);
for(int k=18;k>=0;k--)if(dep[fw[v][k]]>dep[u_v])
v=fw[v][k],ans[smin[t].id]+=(1<<k);
ans[smin[t].id]+=(dis[u]+dis[v]-2*dis[u_v]+i-1)/i;
}
}
for(int i=1;i<=totmax;i++){
int u=smax[i].u,v=smax[i].v,u_v=lca(u,v),w=smax[i].p,x=v;
if(u==v)continue;
while(dis[u]-dis[以上是关于[CodeChef Trips]Children Trips的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode 2187. Minimum Time to Complete Trips