码迷,mamicode.com
首页 > 其他好文 > 详细

【CODECHEF】Children Trips 倍增

时间:2019-02-05 22:10:50      阅读:125      评论:0      收藏:0      [点我收藏+]

标签:int   turn   ace   时间复杂度   font   一个人   swap   pre   std   

此题绝了,$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\n",ans[i]);
85 }

 

【CODECHEF】Children Trips 倍增

标签:int   turn   ace   时间复杂度   font   一个人   swap   pre   std   

原文地址:https://www.cnblogs.com/xiefengze1/p/10353203.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!