codeforces gym #101161E - ACM Tax(lca+主席树)
题目链接:
http://codeforces.com/gym/101161/attachments
题意:
给出节点数为$n$的树
有$q$次询问,输出$a$节点到$b$节点路程中,经过的边的中位数
数据范围:
$1\leq n \leq 100000$
$1\leq q \leq 100000$
分析:
建一颗主席树,不同的是,节点的根继承的是父节点的根
再用$lca$求出公共祖先$tree[a]+tree[b]-2*tree[lca(a,b)]$
ac代码:
#include<bits/stdc++.h> using namespace std; #define ll long long #define pii pair<int,int> const int maxn = 5e4+100; struct Node{ int L,R,num; }tree[maxn*20]; int dep[maxn],fa[maxn][20],n,cnt; int root[maxn],vis[maxn]; vector<pii>ve[maxn]; void update(int x,int&root,int st,int en){ tree[++cnt]=tree[root]; root=cnt; tree[root].num++; if(st==en)return ; int md=(st+en)/2; if(x<=md) update(x,tree[root].L,st,md); else update(x,tree[root].R,md+1,en); } void dfs(int x,int fx,int w){ if(vis[x])return ; vis[x]=1; root[x]=root[fx]; if(x!=1)update(w,root[x],1,1e5); dep[x]=dep[fx]+1; fa[x][0]=fx; for(int i=1;(1<<i)<dep[x];i++) fa[x][i]=fa[fa[x][i-1]][i-1]; for(int i=0;i<ve[x].size();i++) dfs(ve[x][i].first,x,ve[x][i].second); } int lca(int a,int b){ if(dep[a]>dep[b])swap(a,b); for(int i=19;i>=0;i--) if(dep[fa[b][i]]>=dep[a])b=fa[b][i]; if(a==b)return a; for(int i=19;i>=0;i--) if(fa[a][i]!=fa[b][i])a=fa[a][i],b=fa[b][i]; return fa[a][0]; } int quer(int a,int b,int c,int st,int en,int k){ if(st==en)return st; int dd=tree[tree[a].L].num+tree[tree[b].L].num-2*tree[tree[c].L].num; //cout<<dd<<" "<<k<<endl; int md=(st+en)/2; if(dd>=k)return quer(tree[a].L,tree[b].L,tree[c].L,st,md,k); return quer(tree[a].R,tree[b].R,tree[c].R,md+1,en,k-dd); } int main() { int T,q; scanf("%d",&T); while(T--){ scanf("%d",&n); cnt=0; for(int i=1;i<=n;i++){ ve[i].clear(); vis[i]=0; for(int j=0;j<20;j++) fa[i][j]=0; } for(int i=1;i<=n-1;i++){ int a,b,c; scanf("%d %d %d",&a,&b,&c); ve[a].push_back(make_pair(b,c)); ve[b].push_back(make_pair(a,c)); } dfs(1,0,-1); //cout<<fa[6][2]<<endl; scanf("%d",&q); while(q--){ int a,b,c; scanf("%d %d",&a,&b); c=lca(a,b); int len=dep[a]+dep[b]-2*dep[c]; //cout<<c<<" "<<len<<endl; if(len%2==0){ int ans1=quer(root[a],root[b],root[c],1,1e5,len/2); int ans2=quer(root[a],root[b],root[c],1,1e5,len/2+1); printf("%d",(ans1+ans2)/2); if((ans1+ans2)%2)printf(".5"); else printf(".0"); } else printf("%d.0",quer(root[a],root[b],root[c],1,1e5,len/2+1)); printf("\n"); } } return 0; }