• E


    主席树的入门题目,这道题的题意其实就是说,给你一棵树,询问在两个节点之间的路径上的区间第K小

    我们如何把树上问题转换为区间问题呢?

    其实DFS就可以,我们按照DFS的顺序,对线段树进行建树,那么这个树上问题就可以转换为区间问题了,

    那么如何询问来表示两个节点之间的路径呢?

    其实也很简单,可以看看以下的图。。。

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<vector>
    #include<algorithm>
    #define LL long long
    #define rep(i,j,k) for(int i=j;i<=k;i++)
    #define per(i,j,k) for(int i=j;i>=k;i--)
    #define pb push_back
    using namespace std;
    const int maxx = 100005;
    struct node{
       int l,r,cnt;
    }tree[maxx*40];
    inline int MID(int l,int r){return (l+r)>>1;};
    int root[maxx*40];
    int a[maxx];
    int ver[maxx*2],Next[maxx*2],head[maxx];
    int tot,cnt,n,m;
    int t=18;
    int fa[maxx],p[maxx][20],deepth[maxx];
    vector<int>v;
    void add(int x,int y){
       ver[++tot]=y;Next[tot]=head[x];head[x]=tot;
       ver[++tot]=x;Next[tot]=head[y];head[y]=tot;
    }
    void update(int l,int r,int pre,int &now,int pos){
       now=++cnt;
       tree[now]=tree[pre];
       tree[now].cnt++;
       if (l==r)return;
       int mid=(l+r)>>1;
       if (pos<=mid)
        update(l,mid,tree[pre].l,tree[now].l,pos);
       else
        update(mid+1,r,tree[pre].r,tree[now].r,pos);
    }
    int query(int l,int r,int L,int R,int k,int lca,int flac){
       if (l==r)return l;
       int tmp=tree[tree[R].l].cnt+tree[tree[L].l].cnt-tree[tree[lca].l].cnt-tree[tree[flac].l].cnt;
       int mid=MID(l,r);
       if (k<=tmp)
         return query(l,mid,tree[L].l,tree[R].l,k,tree[lca].l,tree[flac].l);
       else
         return query(mid+1,r,tree[L].r,tree[R].r,k-tmp,tree[lca].r,tree[flac].r);
    }
    void dfs(int u,int pre){
       fa[u]=pre;
       deepth[u]=deepth[pre]+1;
       p[u][0]=pre;
       update(1,n,root[pre],root[u],a[u]);
       rep(i,1,18)p[u][i]=p[p[u][i-1]][i-1];
       for (int i=head[u];i;i=Next[i]){
          int y=ver[i];
          if (y==pre)continue;
          dfs(y,u);
       }
    }
    int LCA(int x,int y){
       if (deepth[x]>deepth[y])swap(x,y);
       per(i,t,0){
         if (deepth[p[y][i]]>=deepth[x])y=p[y][i];
       }
       if (x==y)return y;
       per(i,t,0){
          if(p[x][i]!=p[y][i])x=p[x][i],y=p[y][i];
       }
       return p[x][0];
    }
    int main(){
        while(~scanf("%d%d",&n,&m)){
            int uu,vv;
            memset(head,0,sizeof(head));
            rep(i,1,n){
              scanf("%d",&a[i]);
              v.pb(a[i]);
            }
            tot=1;
            cnt=0;
            sort(v.begin(),v.end());
            v.erase(unique(v.begin(),v.end()),v.end());
            rep(i,1,n-1){
              scanf("%d%d",&uu,&vv);
              add(uu,vv);
            }
            rep(i,1,n){
              a[i]=lower_bound(v.begin(),v.end(),a[i])-v.begin()+1;
            }
            dfs(1,0);
            int k;
            while(m--){
                scanf("%d%d%d",&uu,&vv,&k);
                int lca=LCA(uu,vv);
                printf("%d
    ",v[query(1,n,root[uu],root[vv],k,root[lca],root[fa[lca]])-1]);
            }
        }
       return 0;
    }
    有不懂欢迎咨询 QQ:1326487164(添加时记得备注)
  • 相关阅读:
    charindex代替like并非"更快更全面"
    SQLServer2005中的几个统计技巧
    SQLServer获取Excel中所有Sheet
    SQLServer2005的查询独占模拟
    SSAS事实表和维度表数据类型必须一致
    monodevelop 出现has line endings which differ from the policy settings.的解决方法
    mono for android Main.axml
    vs2010 错误提示框:文件加载 使用 简体中文(GB2312
    在Virtual Machine上运行Hello China的方法和工具
    embed基本语法
  • 原文地址:https://www.cnblogs.com/bluefly-hrbust/p/11328664.html
Copyright © 2020-2023  润新知