zoukankan      html  css  js  c++  java
  • SPOJ-COT-Count on a tree(树上路径第K小,可持久化线段树)

    题意:

    求树上A,B两点路径上第K小的数

    分析:

    同样是可持久化线段树,只是这一次我们用它来维护树上的信息。

    我们之前已经知道,可持久化线段树实际上是维护的一个前缀和,而前缀和不一定要出现在一个线性表上。

    比如说我们从一棵树的根节点进行DFS,得到根节点到各节点的距离dist[x]——这是一个根-x路径上点与根节点距离的前缀和。

    利用这个前缀和,我们可以解决一些树上任意路径的问题,比如在线询问[a,b]点对的距离——答案自然是dist[a]+dist[b]-2*dist[lca(a,b)]。

    同理,我们可以利用可持久化线段树来解决树上任意路径的问题。

    DFS遍历整棵树,然后在每个节点上建立一棵线段树,某一棵线段树的“前一版本”是位于该节点父亲节点fa的线段树。

    利用与之前类似的方法插入点权(排序离散)。那么对于询问[a,b],答案就是root[a]+root[b]-root[lca(a,b)]-root[fa[lca(a,b)]]上的第k大。

    // File Name: cot.cpp
    // Author: Zlbing
    // Created Time: 2013年10月09日 星期三 19时24分55秒
    
    #include<iostream>
    #include<string>
    #include<algorithm>
    #include<cstdlib>
    #include<cstdio>
    #include<set>
    #include<map>
    #include<vector>
    #include<cstring>
    #include<stack>
    #include<cmath>
    #include<queue>
    using namespace std;
    #define CL(x,v); memset(x,v,sizeof(x));
    #define INF 0x3f3f3f3f
    #define LL long long
    #define REP(i,r,n) for(int i=r;i<=n;i++)
    #define RREP(i,n,r) for(int i=n;i>=r;i--)
    const int MAXN=1e5+100;
    const int POW=18;
    int num[MAXN],hash[MAXN];
    int ls[MAXN*20],rs[MAXN*20];
    int sum[MAXN*20];
    int root[MAXN];
    vector<int> G[MAXN];
    int d[MAXN];
    int p[MAXN][POW];
    int tot;
    int f[MAXN];
    void build(int l,int r,int& rt)
    {
        rt=++tot;
        sum[rt]=0;
        if(l>=r)return;
        int m=(l+r)>>1;
        build(l,m,ls[rt]);
        build(m+1,r,rs[rt]);
    }
    void update(int last,int p,int l,int r,int &rt)
    {
        rt=++tot;
        ls[rt]=ls[last];
        rs[rt]=rs[last];
        sum[rt]=sum[last]+1;
        if(l>=r)return ;
        int m=(l+r)>>1;
        if(p<=m)update(ls[last],p,l,m,ls[rt]);
        else update(rs[last],p,m+1,r,rs[rt]);
    }
    int query(int left_rt,int right_rt,int lca_rt,int lca_frt,int l,int r,int k)
    {
        if(l>=r)return l;
        int m=(l+r)>>1;
        int cnt=sum[ls[right_rt]]+sum[ls[left_rt]]-sum[ls[lca_rt]]-sum[ls[lca_frt]];
        if(k<=cnt)
            return query(ls[left_rt],ls[right_rt],ls[lca_rt],ls[lca_frt],l,m,k);
        else 
            return query(rs[left_rt],rs[right_rt],rs[lca_rt],rs[lca_frt],m+1,r,k-cnt);
    }
    void dfs(int u,int fa,int cnt)
    {
        f[u]=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];
    
        update(root[fa],num[u],1,cnt,root[u]);
        for(int i=0;i<(int)G[u].size();i++)
        {
            int v=G[u][i];
            if(v==fa)continue;
            dfs(v,u,cnt);
        }
    }
    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;
    }
    int main()
    {
            int n,m;
        while(~scanf("%d%d",&n,&m))
        {
            REP(i,0,n)
            {
                G[i].clear();
            }
            CL(d,0);
            CL(p,0);
            CL(f,0);
            REP(i,1,n)
            {
                scanf("%d",&num[i]);
                hash[i]=num[i];
            }
            tot=0;
            sort(hash+1,hash+1+n);
            int cnt=unique(hash+1,hash+n+1)-hash-1;
            REP(i,1,n)
            {
                num[i]=lower_bound(hash+1,hash+cnt+1,num[i])-hash;
            }
            int a,b,c;
            REP(i,1,n-1)
            {
                scanf("%d%d",&a,&b);
                G[a].push_back(b);
                G[b].push_back(a);
            }
            build(1,cnt,root[0]);
            dfs(1,0,cnt);
            REP(i,1,m)
            {
                scanf("%d%d%d",&a,&b,&c);
                int t=lca(a,b);
                int id=query(root[a],root[b],root[t],root[f[t]],1,cnt,c);
                printf("%d
    ",hash[id]);
            }
        }
        return 0;
    }
  • 相关阅读:
    Java实现 蓝桥杯 算法提高 特等奖学金(暴力)
    Java实现 蓝桥杯 算法提高 特等奖学金(暴力)
    Java实现 蓝桥杯 算法提高 GPA(暴力)
    Java实现 蓝桥杯 算法提高 GPA(暴力)
    Java实现 蓝桥杯 算法提高 GPA(暴力)
    Java实现 蓝桥杯 算法提高 套正方形(暴力)
    Java实现 蓝桥杯 算法提高 套正方形(暴力)
    第一届云原生应用大赛火热报名中! helm install “一键安装”应用触手可及!
    云原生时代,2个方案轻松加速百万级镜像
    Knative 基本功能深入剖析:Knative Serving 自动扩缩容 Autoscaler
  • 原文地址:https://www.cnblogs.com/arbitrary/p/3360104.html
Copyright © 2011-2022 走看看