[BZOJ 2588] Count on a tree

[题目链接]

           https://www.lydsy.com/JudgeOnline/problem.php?id=2588

[算法]

         如果我们能知道“u到v这条路径上权值<= k的数的个数” ,  那么就可以通过二分的方式求出答案

         进一步地 , u到v路径上权值<= k的数的个数 = u到根节点路径上权值<= k的数的个数 + v到根节点路径上权值<= k的数的个数 - u和v的最近公共祖先到根节点路径上权值<= k的数的个数 - u和v的最近公共祖先的父节点到根节点路径上权值<= k的数的个数 

         建立可持久化线段树 , 查询时在线段树上二分即可

         时间复杂度 : O(NlogN)

[代码]

        

#include<bits/stdc++.h>
using namespace std;
#define MAXN 100010
#define MAXLOG 20
typedef long long ll;
typedef long double ld;

struct edge
{
        int to , nxt;
} e[MAXN << 1];

int n , q , len , idx , tot;
int lson[MAXN * 20] , rson[MAXN * 20] , sum[MAXN * 20] , depth[MAXN] , head[MAXN] , root[MAXN] , son[MAXN] , size[MAXN] , fa[MAXN] , top[MAXN];
int a[MAXN] , tmp[MAXN];
int up[MAXN][MAXLOG];

template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
template <typename T> inline void read(T &x)
{
    T f = 1; x = 0;
    char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
    for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
    x *= f;
}
inline void addedge(int u , int v)
{
        ++tot;
        e[tot] = (edge){v , head[u]};
        head[u] = tot;
}
inline void build(int &k , int l , int r)
{
    k = ++idx;
    if (l == r) return;
    int mid = (l + r) >> 1;
    build(lson[k] , l , mid);
    build(rson[k] , mid + 1 , r);
}
inline void modify(int &k , int old , int l , int r , int pos , int value)
{
    k = ++idx;
    lson[k] = lson[old] , rson[k] = rson[old];
    sum[k] = sum[old] + value;
    if (l == r) return;
    int mid = (l + r) >> 1;
    if (mid >= pos) modify(lson[k] , lson[k] , l , mid , pos , value);
    else modify(rson[k] , rson[k] , mid + 1 , r , pos , value);        
}
inline int query(int rt1 , int rt2 , int rt3 , int rt4 , int l , int r , int k)
{
        if (l == r) return l;
        int value = sum[lson[rt1]] + sum[lson[rt2]] - sum[lson[rt3]] - sum[lson[rt4]];
        int mid = (l + r) >> 1;
        if (value >= k) return query(lson[rt1] , lson[rt2] , lson[rt3] , lson[rt4] , l , mid , k);
        else return query(rson[rt1] , rson[rt2] , rson[rt3] , rson[rt4] , mid + 1 , r , k - value);
}
inline void dfs1(int u , int father)
{
        size[u] = 1;
        depth[u] = depth[father] + 1;
        modify(root[u] , root[father] , 1 , len , a[u] , 1);
        for (int i = head[u]; i; i = e[i].nxt)
        {
                int v = e[i].to;
                if (v == father) continue;
                dfs1(v , u);
                fa[v] = u;
                size[u] += size[v];
                if (son[u] == 0 || size[v] > size[son[u]]) son[u] = v; 
        }
}
inline void dfs2(int u , int tp)
{
        top[u] = tp;
        if (son[u]) dfs2(son[u] , tp);
        for (int i = head[u]; i; i = e[i].nxt)
        {
                int v = e[i].to;
                if (v != son[u] && v != fa[u]) dfs2(v , v);
        }
}
inline int lca(int x , int y)
{
        while (top[x] != top[y])
        {
                if (depth[top[x]] > depth[top[y]]) swap(x , y);
                y = fa[top[y]];
        }
        if (depth[x] < depth[y]) return x;
        else return y;
}
inline int getans(int u , int v , int k)
{
        int t1 = lca(u , v) , t2 = fa[t1];
        return query(root[u] , root[v] , root[t1] , root[t2] , 1 , len , k);
}

int main()
{
        
        read(n); read(q);
        for (int i = 1; i <= n; i++) 
        {
                read(a[i]);
                tmp[i] = a[i];
        }
        for (int i = 1; i < n; i++)
        {
                int x , y;
                read(x); read(y);
                addedge(x , y);
                addedge(y , x);
        }
        sort(tmp + 1 , tmp + n + 1);
        len = unique(tmp + 1 , tmp + n + 1) - tmp - 1;
        for (int i = 1; i <= n; i++) a[i] = lower_bound(tmp + 1 , tmp + len + 1 , a[i]) - tmp;
        build(root[0] , 1 , len);
        dfs1(1 , 0);
        dfs2(1 , 1);
        int lastans = 0;
        while (q--)
        {
                int u , v , k;
                read(u); read(v); read(k);
                u ^= lastans;
                printf("%d\n" , lastans = tmp[getans(u , v , k)]);
        }
        
        return 0;
    
}

 

posted @ 2018-11-30 22:00  evenbao  阅读(180)  评论(0编辑  收藏  举报