Gym 101161E 主席树+LCA

来源:互联网 发布:中国经济实力 知乎 编辑:程序博客网 时间:2024/05/17 12:02

题意

给一棵树,问树上路径权值中位数。

题解

树上路径权值中位数就是求第k/2大数,很明显主席树+LCA。这道题还是比较容易的,有一点非常重要的是权值W的范围是1-100000,这个范围很大程度上影响了题目的实现难度。由于权值最大只有10万,因此我们可以搞一个10万的主席树,这样的话每一次查询第K大,我们可以利用主席树去针对某一段版本的线段树去查询,从右到左的第K的数字就是第K大。
搞明白了这个,还有一个需要搞明白的就是树上的查询需要用v[a]+v[b]-2*v[lca(a,b)]。这样一减求的就是路径上的值。

代码

#include<bits/stdc++.h>#define UP(i,l,h) for(int i=l;i<h;i++)#define DOWN(i,h,l) for(int i=h-1;i>=l;i--)#define W(t) while(t)#define MEM(a,b) memset(a,b,sizeof(a))#define LL long long#define INF 0x3f3f3f3f#define EPS 1e-8#define MAXN 50010#define MOD 100000007#define COUT(x) cout<<x<<endlusing namespace std;struct Edge{    int to,w;    Edge(int to=0,int w=0):to(to),w(w){}};vector<Edge> vc[MAXN];const int NN=25001000;int dep[MAXN],sum[NN],ln[NN],rn[NN],root[MAXN];int anc[MAXN][25];int tot;int update(int o,int L,int l,int r){//    COUT(o<<" "<<l<<" "<<r);    int k=++tot;    sum[k]=sum[o],ln[k]=ln[o],rn[k]=rn[o];    sum[k]++;    if(l==r) return k;    int m=(l+r)/2;    if(L<=m) ln[k]=update(ln[k],L,l,m);    else rn[k]=update(rn[k],L,m+1,r);    return k;}int query(int a,int b,int f,int L,int l,int r){    if(l==r) return l;    int m=(l+r)/2;    int tmp=(sum[ln[b]]+sum[ln[a]]-2*sum[ln[f]]);    if(L<=tmp) return query(ln[a],ln[b],ln[f],L,l,m);    else return query(rn[a],rn[b],rn[f],L-tmp,m+1,r);}void dfs(int u,int f,int deep){//    COUT("dfs"<<u);    dep[u]=deep;    anc[u][0]=f;//    COUT(u<<" "<<f);    UP(i,1,20){        anc[u][i]=anc[anc[u][i-1]][i-1];    }    for(Edge v:vc[u]){        if(f==v.to) continue;        root[v.to]=update(root[u],v.w,1,100000);        dfs(v.to,u,deep+1);    }}int lca(int a,int b){    if(dep[a]<dep[b]) swap(a,b);//    COUT(a<<" "<<b);    DOWN(i,20,0){//        COUT(dep[anc[a][i]]<<" "<<dep[b]);        if(dep[b]<=dep[anc[a][i]]) a=anc[a][i];    }//    COUT(a<<" "<<b);    if(a==b) return a;    DOWN(i,20,0){        if(anc[a][i]!=anc[b][i]){            a=anc[a][i];            b=anc[b][i];        }    }    return anc[a][0];}int main(){    int t;    scanf("%d",&t);    W(t--){        MEM(vc,0);        MEM(anc,0);        MEM(dep,0);        MEM(sum,0);        MEM(ln,0);        MEM(rn,0);        MEM(root,0);        tot=0;        int n,q;        scanf("%d",&n);        UP(i,0,n-1){            int u,v,w;             scanf("%d%d%d",&u,&v,&w);             vc[u].push_back(Edge(v,w));             vc[v].push_back(Edge(u,w));        }        scanf("%d",&q);        dfs(1,0,1);        W(q--){            int a,b;            scanf("%d%d",&a,&b);            int fa=lca(a,b);//            COUT(dep[a]<<" "<<dep[b]);//            COUT(fa);            int cot=dep[a]+dep[b]-2*dep[fa];//            COUT(cot);            if(cot%2==1){                printf("%.1f\n",(double)query(root[a],root[b],root[fa],(cot+1)/2,1,100000));            }else{//                COUT((double)query(root[a],root[b],root[fa],cot/2,1,100000)<<" "<<(double)query(root[a],root[b],root[fa],cot/2+1,1,100000));                printf("%.1f\n",((double)query(root[a],root[b],root[fa],cot/2,1,100000)+(double)query(root[a],root[b],root[fa],cot/2+1,1,100000))/2);            }        }    }}