SPOJ Count on a tree(主席树+LCA)

一、题目

  

COT - Count on a tree

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
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


题目链接:http://www.spoj.com/problems/COT/

二、思路
  原理其实和一维线性表序列的一样。只不过这是在树上操作。
  在一维线性表序列中,扫描序列中每一个离散化后的数字,每一次新建的权值线段树都是基于前一次的。而在树中,对每一个子节点的数字,新建的线段树都是基于父节点的线段树的。

***************************
未完待续……  
***************************
 三、源代码
#pragma GCC optimize(2)
#pragma comment(linker, "/STACK:102400000, 102400000")
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define MAXN 111111
LL n, q, m;
/*************树部分*******************/
typedef struct {
    int to, next;
} Edge;
Edge tree[MAXN * 2];
int head[MAXN], ecnt;

void add(int from, int to) {
    tree[ecnt].to = to;
    tree[ecnt].next = head[from];
    head[from] = ecnt++;
}
/*************树部分*******************/
/*************LCA部分*******************/
int parent[MAXN][20], depth[MAXN];
void dfs4lca(int r, int par, int d) {
    parent[r][0] = par, depth[r] = d;
    for(int i = head[r]; i != -1; i = tree[i].next) {
        int to = tree[i].to;
        if(to != par)
            dfs4lca(to, r, d + 1);
    }
}
void init4lca() {
    dfs4lca(1, -1, 0);
    for(int k = 0; k < 19; ++k) {
        for(int v = 1; v <= n; ++v) {
            if(parent[v][k] < 0)
                parent[v][k + 1] = -1;
            else
                parent[v][k + 1] = parent[parent[v][k]][k];
        }
    }
}
int lca(int a, int b) {
    if(depth[a] < depth[b])
        swap(a, b);
    for(int i = 0; i < 20; ++i) {
        if(((depth[a] - depth[b]) >> i) & 1)
            a = parent[a][i];
    }
    if(a == b)
        return a;

    for(int i = 19; i >= 0; --i) {
        if(parent[a][i] != parent[b][i]) {
            a = parent[a][i];
            b = parent[b][i];
        }
    }
    return parent[a][0];
}
/*************LCA部分*******************/
/*************主席树部分*******************/
struct {
    int lch, rch, cnt;
} nodes[MAXN * 20];
int root[MAXN], ncnt;

void update(int &nroot, int proot, int val, int l = 1, int r = m) {
    if(!nroot) {
        nroot = ++ncnt;
        nodes[nroot].cnt = nodes[proot].cnt + 1;
    }
    if(l == r)
        return;
    int mid = (l + r) >> 1;
    if(val <= mid) {
        nodes[nroot].rch = nodes[proot].rch;
        update(nodes[nroot].lch, nodes[proot].lch, val, l, mid);
    } else {
        nodes[nroot].lch = nodes[proot].lch;
        update(nodes[nroot].rch, nodes[proot].rch, val, mid + 1, r);
    }
}
int query(int uroot, int vroot, int lcaroot, int lcafroot, int k, int l = 1, int r = m) {
    if(l == r)
        return l;
    int cnt = nodes[nodes[uroot].lch].cnt + nodes[nodes[vroot].lch].cnt
              - nodes[nodes[lcaroot].lch].cnt - nodes[nodes[lcafroot].lch].cnt;
    int mid = (l + r) >> 1;
    if(k <= cnt)
        return query(nodes[uroot].lch, nodes[vroot].lch, nodes[lcaroot].lch, nodes[lcafroot].lch, k, l, mid);
    else
        return query(nodes[uroot].rch, nodes[vroot].rch, nodes[lcaroot].rch, nodes[lcafroot].rch, k - cnt, mid + 1, r);
}
/*************主席树部分*******************/
/*************离散化部分*******************/
LL weight[MAXN], buf[MAXN], mp[MAXN];
int nwt[MAXN];
void discrete() {
    memcpy(buf + 1, weight + 1, sizeof(weight[0]) * n);
    sort(buf + 1, buf + n + 1);
    m = unique(buf + 1, buf + n + 1) - buf - 1;
    for(int i = 1; i <= n; ++i) {
        nwt[i] = lower_bound(buf + 1, buf + m + 1, weight[i]) - buf;
        mp[nwt[i]] = weight[i];
    }
}
/*************离散化部分*******************/
template <class T> inline void read(T &x) {
    int t;
    bool flag = false;
    while((t = getchar()) != '-' && (t < '0' || t > '9')) ;
    if(t == '-')
        flag = true, t = getchar();
    x = t - '0';
    while((t = getchar()) >= '0' && t <= '9')
        x = x * 10 + t - '0';
    if(flag)
        x = -x;
}


void init() {
    memset(head, -1, sizeof(head));
    ecnt = 0;
    //nodes = 0, root = 0, ncnt = 0;
}

void dfs4tree(int r, int par) {
    for(int i = head[r]; i != -1; i = tree[i].next) {
        int to = tree[i].to;
        if(to != par) {
            update(root[to], root[r], nwt[to]);
            dfs4tree(to, r);
        }
    }
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
#endif // ONLINE_JUDGE
    init();
    LL a, b, u, v, k, wt, uvlca, ans;
    scanf("%lld%lld", &n, &q);
    for(int i = 1; i <= n; ++i) {
        read(weight[i]);
    }
    for(int i = 1; i < n; ++i) {
        read(a), read(b);
        add(a, b);
        add(b, a);
    }
    init4lca();
    discrete();

    add(0, 1);//添加一条虚边。
    dfs4tree(0, -1);

    while(q--) {
        read(u), read(v), read(k);
        uvlca = LL(lca(u, v));
        ans = mp[query(root[u], root[v], root[uvlca], root[parent[uvlca][0]], int(k))];
        printf("%lld\n", ans);
    }
    return 0;
}
 
  

 

 

转载于:https://www.cnblogs.com/fuzhihong0917/p/8331158.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值