SPOJ 10628. SPOJ COT Count on a tree

Posted Splay

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SPOJ 10628. SPOJ COT Count on a tree相关的知识,希望对你有一定的参考价值。

  这题是裸的主席树,每个节点建一棵主席树,再加个lca就可以了。

  历尽艰辛,终于A掉了这一题,这般艰辛也显示出了打代码的不熟练。

  错误:1、lca倍增的时候i和j写反了,RE了5次,实在要吸取教训

     2、主席树插入操作的时候,如果插入到的那个点(叶节点)原来有值,而没有加上,导致了WA

  以下是历尽艰辛的代码,还很长。

 

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <map>

using namespace std;

const int maxn = 100005;
int n, m, w[maxn];
int head[maxn], label;
struct Edge
{
    int v, next;
    Edge (int v = 0, int next = 0):
        v(v), next(next) {}
}e[maxn*2];
int depth[maxn], f[maxn][31], root[maxn], temp[maxn], s_num;
queue <int> q;
map <int, int> id;
struct Tree
{
    int sum[maxn*20], ls[maxn*20], rs[maxn*20], cnt;
    Tree ()
    {
        sum[0] = 0, cnt = 0;
    }
    void PushUp(int rt)
    {
        sum[rt] = sum[ls[rt]]+sum[rs[rt]];
    }
    void insert(int las_rt, int rt, int l, int r, int p, int d)
    {
        if (l == r)
        {
            sum[rt] = sum[las_rt]+d;
            return ;
        }
        int mid = (l+r)>>1;
        if (p <= mid)
        {
            ls[rt] = ++cnt, rs[rt] = rs[las_rt];
            insert(ls[las_rt], ls[rt], l, mid, p, d);
        }
        else
        {
            ls[rt] = ls[las_rt], rs[rt] = ++cnt;
            insert(rs[las_rt], rs[rt], mid+1, r, p, d);
        }
        PushUp(rt);
    }
    int query(int u_rt, int v_rt, int lca_rt, int lca_pos, int l, int r, int k)
    {
        if (l == r)
            return l;
        int mid = (l+r)>>1;
        int s_l = sum[ls[u_rt]]+sum[ls[v_rt]]-2*sum[ls[lca_rt]]+(lca_pos >= l && lca_pos <= mid);
        if (k <= s_l)
            return query(ls[u_rt], ls[v_rt], ls[lca_rt], lca_pos, l, mid, k);
        else
            return query(rs[u_rt], rs[v_rt], rs[lca_rt], lca_pos, mid+1, r, k-s_l);
    }
}T;

void ins(int u, int v)
{
    e[++label] = Edge(v, head[u]);
    head[u] = label;
}

void in()
{
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; ++i)
        scanf("%d", &w[i]);
    for (int i = 1; i <= n; ++i)
        head[i] = -1;
    label = -1;
    for (int i = 1; i < n; ++i)
    {
        int u, v;
        scanf("%d %d", &u, &v);
        ins(u, v), ins(v, u);
    }
}

void Build_lca()
{
    for (int i = 0; i <= 30; ++i)
        for (int j = 1; j <= n; ++j)
            f[j][i] = -1;
    q.push(1);
    depth[1] = 0;
    f[1][0] = -1;
    while (!q.empty())
    {
        int u = q.front();
        for (int i = head[u]; i != -1; i = e[i].next)
        {
            int v = e[i].v;
            if (v == f[u][0])
                continue ;
            f[v][0] = u;
            depth[v] = depth[u]+1;
            q.push(v);
        }
        q.pop();
    }
    for (int i = 1; i <= 30; ++i)
        for (int j = 1; j <= n; ++j)
        {
            if (f[j][i-1] == -1)
                continue ;
            f[j][i] = f[f[j][i-1]][i-1];
        }    
}

void Hash_a()
{
    for (int i = 1; i <= n; ++i)
        temp[i] = w[i];
    sort(temp+1, temp+n+1);
    s_num = 0;
    for (int i = 1; i <= n; ++i)
        if (temp[i] != temp[i-1] || i == 1)
        {
            temp[++s_num] = temp[i];
            id[temp[i]] = s_num;
        }
}

void dfs(int u)
{
    root[u] = ++T.cnt;
    T.insert(u == 1 ? 0 : root[f[u][0]], root[u], 1, s_num, id[w[u]], 1);
    for (int i = head[u]; i != -1; i = e[i].next)
    {
        int v = e[i].v;
        if (v == f[u][0])
            continue ;
        dfs(v);
    }
}

void Build_tree()
{
    Hash_a();
    dfs(1);/*
    for (int i = 1; i <= n; ++i)
        printf("%d %d\n", i, T.sum[root[i]]);*/
}

void prepare()
{
    Build_lca();
    Build_tree();
}

int lca(int u, int v)
{
    if (depth[u] < depth[v])
        swap(u, v);
    for (int i = 30; i >= 0; --i)
    {
        if (f[u][i] == -1)
            continue ;
        if (depth[f[u][i]] >= depth[v])
        {
            u = f[u][i];
            if (depth[u] == depth[v])
                break ;
        }
    }
    if (u == v)
        return u;
    for (int i = 30; i >= 0; --i)
    {
        if (f[u][i] == -1)
            continue ;
        if (f[u][i] != f[v][i])
        {
            u = f[u][i];
            v = f[v][i];
        }
    }
    return f[u][0];
}

void work()
{
    prepare();
    while (m --)
    {
        int u, v, k;
        scanf("%d %d %d", &u, &v, &k);
        int t = lca(u, v);
        int pos = T.query(root[u], root[v], root[t], id[w[t]], 1, s_num, k);
        printf("%d\n", temp[pos]);
    }
}

int main()
{
    in();
    work();
    return 0;
}

 

  

以上是关于SPOJ 10628. SPOJ COT Count on a tree的主要内容,如果未能解决你的问题,请参考以下文章

SPOJ 10628 Count on a tree(Tarjan离线LCA+主席树求树上第K小)

BZOJ 2588: Spoj 10628. Count on a tree

BZOJ2588 Spoj 10628. Count on a tree

[Spoj 10628]Count on a tree

BZOJ 2588: Spoj 10628. Count on a tree [树上主席树]

[BZOJ2588][Spoj 10628]Count on a tree