题意:给定一棵带权树,Q次询问,每次询问路径上的中位数。
思路:中位数分边数奇偶考虑,当当边数为num=奇时,结果就算路径第num/2+1大,用主席树做即可。。。
(做了几道比较难的主席树,都wa了。。。只有来刷刷水题,准备晚上的CF了)
#include<bits/stdc++.h> using namespace std; const int maxn=1000010; int Laxt[maxn],Next[maxn],To[maxn],cost[maxn],cnt; int fa[50010][20],dep[maxn],rt[maxn],tot; struct in{ int l,r,sum; }s[maxn]; void init() { cnt=0; tot=0; memset(Laxt,0,sizeof(Laxt)); memset(s,0,sizeof(s)); memset(rt,0,sizeof(rt)); } void add(int u,int v,int c){Next[++cnt]=Laxt[u];Laxt[u]=cnt;To[cnt]=v;cost[cnt]=c;} void Add(int &Now,int pre,int L,int R,int pos) { Now=++tot; s[Now]=s[pre]; s[Now].sum++; if(L==R) return ; int Mid=(L+R)>>1; if(pos<=Mid) Add(s[Now].l,s[pre].l,L,Mid,pos); else Add(s[Now].r,s[pre].r,Mid+1,R,pos); } int query(int Now1,int Now2,int pre,int L,int R,int K) { if(L==R) return L; int Mid=(L+R)>>1; int tmp=s[s[Now1].l].sum+s[s[Now2].l].sum-2*s[s[pre].l].sum; if(tmp>=K) return query(s[Now1].l,s[Now2].l,s[pre].l,L,Mid,K); else return query(s[Now1].r,s[Now2].r,s[pre].r,Mid+1,R,K-tmp); } void dfs(int u,int f) { dep[u]=dep[f]+1; fa[u][0]=f; for(int i=Laxt[u];i;i=Next[i]) if(To[i]!=f) { Add(rt[To[i]],rt[u],1,100000,cost[i]); dfs(To[i],u); } } int LCA(int u,int v) { if(dep[u]<dep[v]) swap(u,v); for(int i=19;i>=0;i--) if(dep[fa[u][i]]>=dep[v]) u=fa[u][i]; if(u==v) return u; for(int i=19;i>=0;i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i]; return fa[u][0]; } int main() { int T,N,Q,x,y,c,i,j; scanf("%d",&T); while(T--){ init(); scanf("%d",&N); for(i=1;i<N;i++){ scanf("%d%d%d",&x,&y,&c); add(x,y,c); add(y,x,c); } dfs(1,0); for(i=1;i<20;i++) for(j=1;j<=N;j++) fa[j][i]=fa[fa[j][i-1]][i-1]; scanf("%d",&Q); while(Q--){ scanf("%d%d",&x,&y); int Lca=LCA(x,y); int num=dep[x]-dep[Lca]+dep[y]-dep[Lca]; if(num%2==0){ double aa=query(rt[x],rt[y],rt[Lca],1,100000,num/2); double bb=query(rt[x],rt[y],rt[Lca],1,100000,num/2+1); printf("%.1lf ",(aa+bb)/2); } else { double ans=query(rt[x],rt[y],rt[Lca],1,100000,num/2+1); printf("%.1lf ",ans); } } } return 0; }