CODECHEFChildren Trips 倍增
Posted xiefengze1
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CODECHEFChildren Trips 倍增相关的知识,希望对你有一定的参考价值。
此题绝了,$O(n^{1.5} log n)$都可以过掉。。。。
题目大意:给你一颗$n$个点的树,每条边边权不是2就是$1$,有$m$个询问,每次询问一个人从$x$点走到$y$点,每天可以走的里程数不超过$k$,问你从$x$至$y$至少需几天。
数据范围:$n≤10^5$。
我们将询问分成$k≤sqrt{n}$和k$>sqrt{n}$两类。
对于$k>sqrt{n}$的,每次跳跃我们直接大力倍增就可以了,不难发现此方法单次的时间复杂度为$O(sqrt{n}log n)$。
对于$k≤sqrt{n}$的,我们将$k$相同的分为一类,令$g[i][j]$表示从i往根走$2^j$天走到的位置,然后大力倍增就可以了,不难发现单次倍增找答案的时间复杂度是$O(log n)$的,重建一次倍增数组的时间复杂度是$O(n log n)$的,总时间复杂度为$O(n^{1.5} log n+m log n)$。
如此粗暴的做法居然能在$350ms$跑过去,真是绝了(敢写敢过。。。。)
1 #include<bits/stdc++.h> 2 #define M 100005 3 #define N 17 4 using namespace std; 5 struct edge{int u,v,next;}e[M*2]={0}; int head[M]={0},use=0; 6 void add(int x,int y,int z){use++;e[use].u=y;e[use].v=z;e[use].next=head[x];head[x]=use;} 7 int f[M][N]={0},dep[M]={0},dis[M]={0}; 8 void dfs(int x,int fa,int hh){ 9 f[x][0]=fa; dep[x]=dep[fa]+1; dis[x]=dis[fa]+hh; 10 for(int i=1;i<N;i++) f[x][i]=f[f[x][i-1]][i-1]; 11 for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa) dfs(e[i].u,x,e[i].v); 12 } 13 int getlca(int x,int y){ 14 if(dep[x]<dep[y]) swap(x,y); int cha=dep[x]-dep[y]; 15 for(int i=N-1;~i;i--) if((1<<i)&cha) x=f[x][i]; 16 for(int i=N-1;~i;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; 17 if(x==y) return x; return f[x][0]; 18 } 19 int getdis(int x,int y){return dis[x]+dis[y]-2*dis[getlca(x,y)];} 20 int _j=0; 21 int jumpdn(int x,int y,int d){ 22 int now=dis[y]-dis[x]; if(now<=d) return y; 23 for(int i=N-1;~i;i--) 24 if(dis[f[y][i]]-dis[x]>=d) 25 y=f[y][i]; 26 if(dis[y]-dis[x]>d) y=f[y][0]; 27 return y; 28 } 29 int jumpup(int x,int y,int d){ 30 if(y){ 31 int lca=getlca(x,y); _j=0; 32 if(dis[x]-dis[lca]<=d){ 33 d-=dis[x]-dis[lca]; _j=1; 34 return jumpdn(lca,y,d); 35 } 36 } 37 for(int i=N-1;~i;i--) if(dis[x]-dis[f[x][i]]<=d) d-=dis[x]-dis[f[x][i]],x=f[x][i]; 38 return x; 39 } 40 int g[M][N]={0},D=0; 41 void dfs(int x,int fa){ 42 g[x][0]=jumpup(x,0,D); for(int i=1;i<N;i++) g[x][i]=g[g[x][i-1]][i-1]; 43 for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa) dfs(e[i].u,x); 44 } 45 int query(int &x,int lca){int res=0; 46 for(int i=N-1;~i;i--){ 47 if(dis[x]-dis[lca]<D) return res; 48 if(dep[g[x][i]]>=dep[lca]) x=g[x][i],res+=1<<i; 49 } 50 return res; 51 } 52 int n,m,sq; 53 struct ask{ 54 int x,y,d,id; ask(){x=y=d=id=0;} 55 void rd(int ID){id=ID; scanf("%d%d%d",&x,&y,&d);} 56 friend bool operator <(ask a,ask b){return a.d<b.d;} 57 int query1(){ 58 if(x==y) return 0; 59 int lca=getlca(x,y),res=0; _j=0; 60 while(_j==0) x=jumpup(x,y,d),res++; 61 while(x!=y) x=jumpdn(x,y,d),res++; 62 return res; 63 } 64 int query2(){ 65 int lca=getlca(x,y),res=0; 66 if(D!=d){D=d;dfs(1,0);} 67 res+=query(x,lca); 68 res+=query(y,lca); 69 res+=(getdis(x,y)>D)+(getdis(x,y)>0); 70 return res; 71 } 72 }p[M]; int ans[M]={0}; 73 int main(){ 74 scanf("%d",&n); sq=(n<=1000?0:10); 75 for(int i=1,x,y,z;i<n;i++) scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z); 76 dfs(1,0,0); dis[0]=-1; 77 scanf("%d",&m); 78 for(int i=1;i<=m;i++) p[i].rd(i); 79 sort(p+1,p+m+1); 80 for(int i=1;i<=m;i++){ 81 if(p[i].d<=sq) ans[p[i].id]=p[i].query2(); 82 else ans[p[i].id]=p[i].query1(); 83 } 84 for(int i=1;i<=m;i++) printf("%d ",ans[i]); 85 }
以上是关于CODECHEFChildren Trips 倍增的主要内容,如果未能解决你的问题,请参考以下文章
[CodeChef Trips]Children Trips
LeetCode 2187. Minimum Time to Complete Trips