zoukankan      html  css  js  c++  java
  • 树上第k小,可持久化线段树+倍增lca

    给定一颗树,树的每个结点都有权值,

    有q个询问,每个询问是 u v k ,表示u到v路径上第k小的权值是多少。

    每个结点所表示的线段树,是父亲结点的线段树添加该结点的权值之后形成的新的线段树

    c[root] 表示根为root的子树添加了多少个结点。

    那么c[lson[u]] + c[lson[v]] - c[lson[lca(u,v)]] - c[lson[fa[lca(u,v)]]]  >=k ,那么说明左子树添加了k个以上的结点,说明第k小的值在左子树

    否则就在右子树。

      1 //
      2 //  main.cpp
      3 //  函数式线段树
      4 //
      5 //  Created by whoami on 15/9/21.
      6 //  Copyright (c) 2015年 whoami. All rights reserved.
      7 //
      8 
      9 #include <iostream>
     10 #include <algorithm>
     11 #include <stdio.h>
     12 #include <string.h>
     13 using namespace std;
     14 const int N = 3000000 + 10;
     15 const int M = 200000;
     16 int t[N],lson[N],rson[N],c[N],total;
     17 int a[M],b[M];
     18 int n,m,q;
     19 int head[M],nxt[M],to[M],e;
     20 int dfs_clock,iid[M];
     21 int fa[M][30],depth[M];
     22 void addEdge(int u, int v){
     23     to[e] = v;
     24     nxt[e] = head[u];
     25     head[u] = e++;
     26 }
     27 
     28 //离散化,离散化后有多少个点,线段树的区间就是多大
     29 void initHash(){
     30     sort(b+1,b+n+1);
     31     m = unique(b+1,b+n+1) - b - 1;
     32 }
     33 int hs(int x){
     34     return lower_bound(b+1,b+m+1,x)-b;
     35 }
     36 
     37 int build(int l, int r){
     38     int root = total++;
     39     c[root] = 0;
     40     if(l!=r){
     41         int mid = (l+r)>>1;
     42         lson[root] = build(l,mid);
     43         rson[root] = build(mid+1,r);
     44     }
     45     return root;
     46 }
     47 int update(int root, int pos, int val){
     48     int newRoot = total++,tmp = newRoot;
     49     c[newRoot] = c[root] + val;
     50     int l =1, r = m;
     51     while(l<r){
     52         int mid = (l+r)>>1;
     53         if(pos<=mid){
     54             r = mid;
     55             lson[newRoot] = total++;
     56             rson[newRoot] = rson[root];
     57             newRoot = lson[newRoot];
     58             root = lson[root];
     59         }
     60         else{
     61             l = mid + 1;
     62             lson[newRoot] = lson[root];
     63             rson[newRoot] = total++;
     64             newRoot = rson[newRoot];
     65             root = rson[root];
     66         }
     67         c[newRoot] = c[root] + val;
     68     }
     69     return tmp;
     70 }
     71 void dfs(int u, int f, int dep){
     72     fa[u][0] = f;
     73     depth[u] = dep;
     74 
     75     for(int i=head[u]; i+1;i=nxt[i]){
     76         int v = to[i];
     77         if(v==f)continue;
     78         t[++dfs_clock] = update(iid[u],hs(a[v]),1);
     79         iid[v] = t[dfs_clock];
     80         dfs(v,u,dep+1);
     81     }
     82 }
     83 
     84 int query(int urt, int vrt, int lcart, int frt, int k){
     85     int l = 1, r = m;
     86     //当l==r,即区间的长度只有1时,那么该区间所对应的值就是第k小了
     87     while(l<r){
     88         int mid = (l+r)>>1;
     89         if(c[lson[urt]] + c[lson[vrt]] - c[lson[frt]]-c[lson[lcart]]>=k){
     90             r = mid;
     91             urt = lson[urt];
     92             vrt = lson[vrt];
     93             frt = lson[frt];
     94             lcart = lson[lcart];
     95         }
     96         else
     97         {
     98             l = mid+1;
     99             k -= c[lson[urt]] + c[lson[vrt]] - c[lson[frt]]-c[lson[lcart]];
    100             urt = rson[urt];
    101             vrt = rson[vrt];
    102             frt = rson[frt];
    103             lcart = rson[lcart];
    104         }
    105     }
    106     return l;
    107 }
    108 void init() {
    109     for(int k=0;k+1<25; ++k){
    110         for(int v = 0;v<=n;++v){
    111             if(fa[v][k]<0)
    112                 fa[v][k+1] = -1;
    113             else
    114                 fa[v][k+1] = fa[fa[v][k]][k];
    115         }
    116     }
    117 }
    118 
    119 int lca(int u, int  v){
    120     if(depth[u] < depth[v])
    121         swap(u,v);
    122 
    123     int tmp = depth[u] - depth[v];
    124     for(int i=25;i>=0;--i)
    125         if(tmp &(1<<i))
    126         u = fa[u][i];
    127     if(u==v) return u;
    128     for(int i=25;i>=0;--i){
    129         if(fa[u][i]!=fa[v][i]){
    130             u = fa[u][i];
    131             v = fa[v][i];
    132         }
    133     }
    134     return fa[u][0];
    135 
    136 }
    137 int main(int argc, const char * argv[]) {
    138     int u,v,k;
    139     while(scanf("%d%d",&n,&q)!=EOF){
    140         total = dfs_clock = 0;
    141         for(int i=1;i<=n;++i){
    142             scanf("%d",&a[i]);
    143             b[i] = a[i];
    144         }
    145         memset(head,-1,sizeof(head));
    146         for(int i=1;i<n;++i){
    147             scanf("%d%d",&u,&v);
    148             addEdge(u,v);
    149             addEdge(v,u);
    150         }
    151         addEdge(0,1);
    152         addEdge(1,0);
    153         initHash();
    154         iid[0] = t[0] = build(1,m);
    155         memset(fa,-1,sizeof(fa));
    156         dfs(0,0,1);
    157 
    158         init();
    159         while(q--){
    160             scanf("%d%d%d",&u,&v,&k);
    161             int lc = lca(u,v);
    162             int f = fa[lc][0];
    163             printf("%d
    ",b[query(iid[u],iid[v],iid[lc],iid[f],k)]);
    164         }
    165     }
    166 
    167     return 0;
    168 }
  • 相关阅读:
    java线程的几种状态
    java事务的处理
    Java多线程中Sleep与Wait的区别
    分享一百多套开发视频教程的下载地址
    [Java]读取文件方法大全
    Android开发人员必备的10 个开发工具
    CentOS 安装MySQL rpm方式安装
    记录一些经典的算法
    CentOS 7安装Redis服务
    linux查看文件大小,磁盘占用情况 du df命令
  • 原文地址:https://www.cnblogs.com/justPassBy/p/4831470.html
Copyright © 2011-2022 走看看