SPOJ COT(树上的点权第k大)

Time Limit: 129MS   Memory Limit: 1572864KB   64bit IO Format: %lld & %llu

 Status

Description

You are given a tree with N nodes.The tree nodes are numbered from 1 to N.Each node has an integer weight.

We will ask you to perform the following operation:

  • u v k : ask for the kth minimum weight on the path from node u to node v

Input

In the first line there are two integers N and M.(N,M<=100000)

In the second line there are N integers.The ith integer denotes the weight of the ith node.

In the next N-1 lines,each line contains two integers u v,which describes an edge (u,v).

In the next M lines,each line contains three integers u v k,which means an operation asking for the kth minimum weight on the path from node u to node v.

Output

For each operation,print its result.

Example

Input:
8 5
8 5
105 2 9 3 8 5 7 7
1 2        
1 3
1 4
3 5
3 6
3 7
4 8
2 5 1
2 5 2
2 5 3
2 5 4
7 8 2 
Output:
2
8
9
105
7 

题意:求树上的边[u,v]中点权第k大

使用的是主席树+LCA(RMQ.dfs),然后去专门看了下RMQ+dfs实现LCA

用一个数组记录深度,然后记录搜索的路径,如果要找[a,b]中的LCA,直接找[a,b]中的深度最小值即可

参考:算法之LCA与RMQ问题


/*
主席树-代码参考kuangbin大神
在本题中相当于按树的节点来构建线段树,每个节点基于它的父亲进行构建
然后节点a保存的便是根到a的情况,于是乎我们T[a]+T[b]-2*T[lca(a,b)]即可
而且对lca节点进行一个判断。
hhh-2016-02-18 21:11:14
*/

#include <functional>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>
#include <cmath>
using namespace std;

const int maxn = 200010;
int n,m;
int a[maxn],t[maxn];
int T[maxn*40],val[maxn*40],lson[maxn*40],rson[maxn*40];
int Tot;

void ini_hash() //排序去重
{
    for(int i =1; i <= n; i++)
        t[i] = a[i];
    sort(t+1,t+n+1);
    m = unique(t+1,t+n+1)-t-1;
}

int Hash(int x) //获得x在排序去重后的位置
{
    return lower_bound(t+1,t+m+1,x) - t;
}

int build(int l,int r)
{
    int root = Tot++;
    val[root] = 0;
    if(l != r)
    {
        int mid = (l+r)>>1;
        lson[root] = build(l,mid);
        rson[root] = build(mid+1,r);
    }
    return root;
}


//如果那里发生改变则兴建一个节点而非像平常修改那个节点的值
int update(int root,int pos,int va)
{
    int newroot = Tot++;
    int tmp = newroot;
    val[newroot] = val[root] + va;
    int l = 1,r = m;
    while(l < r)
    {
        int mid = (l+r)>>1;
        if(pos <= mid)
        {
            lson[newroot] = Tot++;
            rson[newroot] = rson[root];
            newroot = lson[newroot];
            root = lson[root];
            r = mid;
        }
        else
        {
            lson[newroot] = lson[root];
            rson[newroot] = Tot++;
            newroot = rson[newroot];
            root = rson[root];
            l = mid+1;
        }
        val[newroot] = val[root] + va;
    }
    return tmp;
}

int query(int lt,int rt,int lca,int k)
{
    int lca_rt = T[lca];
    int pos = Hash(a[lca]);
    int l = 1, r = m;
    while(l < r)
    {
        int mid = (l+r)>>1;
        int tmp = val[lson[lt]]+val[lson[rt]]-2*val[lson[lca_rt]]+(pos>=l&&pos<=mid);
        if(tmp >= k)
        {
            lt = lson[lt];
            rt = lson[rt];
            lca_rt = lson[lca_rt];
            r = mid;
        }
        else
        {
            k -= tmp;
            l = mid+1;
            lt = rson[lt];
            rt = rson[rt];
            lca_rt = rson[lca_rt];
        }
    }
    return l;
}

int rmq[maxn*2]; //表示深度
struct ST
{
    int mm[maxn*2];
    int dp[maxn*2][20];
    void ini(int n)
    {
        mm[0] = -1;
        for(int i = 1; i <= n; i++)
        {
            mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
            dp[i][0] = i;
        }
        for(int j = 1; j <= mm[n]; j++)
            for(int i = 1; i + (1<<j) - 1 <= n; i++)
                dp[i][j] = rmq[dp[i][j-1]] < rmq[dp[i+(1<<(j-1))][j-1]]?
                           dp[i][j-1]:dp[i+(1<<(j-1))][j-1];
    }
    int query(int a,int b)
    {
        if(a > b)swap(a,b);
        int k = mm[b-a+1];
        return rmq[dp[a][k]] <= rmq[dp[b-(1<<k)+1][k]]?
               dp[a][k]:dp[b-(1<<k)+1][k];
    }
};

struct E
{
    int to,next;
} edge[maxn*2];
int tot,head[maxn];
int F[maxn*2];
int P[maxn];
int cnt;
//F表示dfs的序列
//P[i]表示i第一次出现的位置

ST st;
void init() //初始化
{
    Tot = tot = 0;
    memset(head,-1,sizeof(head));
}

void dfs(int u,int pre,int dep)
{
    F[++cnt] = u;
    rmq[cnt] = dep;
    P[u] = cnt;
    for(int i = head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].to;
        if(v == pre)continue;
        dfs(v,u,dep+1);
        F[++cnt] = u;
        rmq[cnt] = dep;
    }
}


void ini_lca(int root,int num)
{
    cnt = 0;
    dfs(root,root,0);
    st.ini(2*num-1);
}

void addedge(int u,int v)
{
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot++;
}

int query_lca(int u,int v)
{
    return F[st.query(P[u],P[v])];
}

void dfs_build(int u,int pre)
{
    int pos = Hash(a[u]);
    T[u] = update(T[pre],pos,1);
    for(int i = head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].to;
        if(v == pre) continue;
        dfs_build(v,u);
    }
}

int main()
{
    int q;
    while(scanf("%d%d",&n,&q) == 2)
    {
        for(int i = 1; i <= n; i++)
            scanf("%d",&a[i]);
        ini_hash();
        init();
        int u,v,k;
        for(int i = 1; i < n; i++)
        {

            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        ini_lca(1,n);
        T[n+1] = build(1,m);
        dfs_build(1,n+1);
        while(q--)
        {
            scanf("%d%d%d",&u,&v,&k);
            printf("%d
",t[query(T[u],T[v],query_lca(u,v),k)]);
        }
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/Przz/p/5409626.html