codeforces 208 E 时间戳 倍增法求LCA
2014-11-20 22:31
375 查看
转:http://blog.csdn.net/crazy_ac/article/details/7796497
链接:http://www.codeforces.com/problemset/problem/208/E
题意:给你一个森林,m个询问:v,p
求有多少个点(除v外) 与 v的第p个祖先相同
这个题首先要解决找某个点的第p个祖先的问题,可以采用倍增法
记录一个二维数组p[u][i]表示u的第2^i个祖先,那么通过这个数组我们就可以知道u的上面任意深度(相对于u)祖先是谁(巧妙的利用二进制)
具体求法和用法见下,还可以找LCA的
假设vp是v的p祖先,那么v 的 p Cousins就是时间戳位于vp的两个时间戳之间深度为dep【v】
的点的个数
链接:http://www.codeforces.com/problemset/problem/208/E
题意:给你一个森林,m个询问:v,p
求有多少个点(除v外) 与 v的第p个祖先相同
这个题首先要解决找某个点的第p个祖先的问题,可以采用倍增法
记录一个二维数组p[u][i]表示u的第2^i个祖先,那么通过这个数组我们就可以知道u的上面任意深度(相对于u)祖先是谁(巧妙的利用二进制)
具体求法和用法见下,还可以找LCA的
/* 2^17=131072; 2^18=262144; */ const int POW = 18; void dfs(int u,int fa){ d[u]=d[fa]+1; p[u][0]=fa; for(int i=1;i<POW;i++) p[u][i]=p[p[u][i-1]][i-1]; int sz=edge[u].size(); for(int i=0;i<sz;i++){ int v=edge[u][i]; if(v==fa) continue; dfs(v,u); } } int lca( int a, int b ){ if( d[a] > d[b] ) a ^= b, b ^= a, a ^= b; if( d[a] < d[b] ){ int del = d[b] - d[a]; for( int i = 0; i < POW; i++ ) if(del&(1<<i)) b=p[b][i]; } if( a != b ){ for( int i = POW-1; i >= 0; i-- ) if( p[a][i] != p[b][i] ) a = p[a][i] , b = p[b][i]; a = p[a][0], b = p[b][0]; } return a; }这道题的话需要记录 每个点的两个时间戳,每个深度的所有时间戳
假设vp是v的p祖先,那么v 的 p Cousins就是时间戳位于vp的两个时间戳之间深度为dep【v】
的点的个数
#include<cstdio> #include<cstring> #include<vector> #include<algorithm> using namespace std; const int maxn = 100010; vector<int> g[maxn]; vector<int> edge[maxn]; vector<int> rt; bool vis[maxn]; int n,m,dfn; int in[maxn],out[maxn]; int dep[maxn],p[maxn][18]; int depth; void dfs(int u,int fa){ vis[u]=true; in[u]=dfn++; //printf("in[%d]=%d\n",u,in[u]); dep[u]=dep[fa]+1; g[dep[u]].push_back(dfn); p[u][0]=fa; for(int i=1;i<18;i++) p[u][i]=p[p[u][i-1]][i-1]; int sz=edge[u].size(); for(int i=0;i<sz;i++){ int v=edge[u][i]; if(v==fa) continue; dfs(v,u); } out[u]=dfn++; //printf("out[%d]=%d\n",u,out[u]); } int solve(int tfn,int d){ int l=0,r=g[d].size()-1,best=-1; while(l<=r){ int m=l+r>>1; if(g[d][m]<=tfn){ l=m+1; best=m; } else r=m-1; } return best+1; } int find(int v,int pp){ for(int i=0;i<18;i++) if(pp&(1<<i)) v=p[v][i]; return v; } int ans[maxn]; int main() { while(scanf("%d",&n)!=EOF) { int fa,v,pp; rt.clear(); memset(p,0,sizeof(p)); memset(dep,0,sizeof(dep)); for(int i=0;i<=n;i++) edge[i].clear(),g[i].clear(); for(int i=1;i<=n;i++) { scanf("%d",&fa); if(fa==0) rt.push_back(i); else edge[fa].push_back(i); } dfn=0;depth=0; for(int i=0;i<rt.size();i++) depth=0,dfs(rt[i],0); scanf("%d",&m); for(int i=0;i<m;i++) { scanf("%d%d",&v,&pp); int vp=find(v,pp); if(!vp) ans[i]=0; else { ans[i]=solve(out[vp],dep[v])-solve(in[vp]-1,dep[v])-1; } } for(int i=0;i<m;i++) printf("%d ",ans[i]); puts(""); } return 0; }
相关文章推荐
- codeforces 208 E 时间戳 倍增法求LCA
- codeforces 733 F. Drivers Dissatisfaction(最小生成树+lca+倍增去环)
- 【Lca 倍增】codeforces 832D Misha, Grisha and Underground
- Codeforces 609E Minimum spanning tree for each edge【MST + LCA倍增】
- CodeForces 609E Minimum spanning tree for each edge (lca+最小生成树+倍增)
- codeforces 587C:(LCA倍增+维护最小值)
- Codeforces 519E A and B and Lecture Rooms [倍增法LCA]
- codeforces 519E A and B and Lecture Rooms(LCA,倍增)
- 【CodeForces】827 D. Best Edge Weight 最小生成树+倍增LCA+并查集
- CodeForces 609 E.Minimum spanning tree for each edge(最小生成树-Kruskal+在线倍增LCA)
- codeforces 519E 倍增法LCA
- CodeForces 406 D.Hill Climbing (凸包-Graham扫描法+在线倍增LCA)
- Codeforces 609E LCA倍增
- Codeforces 418d Big Problems for Organizers [树形dp][倍增lca]
- [BZOJ2815][ZJOI2012]灾难(倍增lca+top)
- LCA三种算法学习(离线算法tarjan+在线算法转rmq+在线倍增)例题poj1330、1470;hdu4547、2874
- LCA Tarjan及倍增模板(POJ 1330)
- CodeForces - 827D [Best Edge Weight] 倍增+最小生成树+并查集
- 【基础练习】【倍增LCA】codevs1036 商务旅行题解
- LCA,有向图求两点间距离,无向图求两点间距离,倍增