bzoj2588 Spoj 10628. Count on a tree

2588: Spoj 10628. Count on a tree

Time Limit: 12 Sec  Memory Limit: 128 MB
Submit: 8100  Solved: 2010
[Submit][Status][Discuss]

Description

给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。
 

Input

第一行两个整数N,M。
第二行有N个整数,其中第i个整数表示点i的权值。
后面N-1行每行两个整数(x,y),表示点x到点y有一条边。
最后M行每行两个整数(u,v,k),表示一组询问。
 

Output

M行,表示每个询问的答案。最后一个询问不输出换行符

Sample 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
0 5 2
10 5 3
11 5 4
110 8 2

Sample Output

2
8
9
105
7

HINT

N,M<=100000

暴力自重。。。

Source

鸣谢seter

分析:挺裸的主席树.每一颗点所代表的主席树建立在它的父节点的基础上.建树就很容易地解决了.查询的话首先要把(u,v)这条链给找出来,就是u到根的路径 + v到根的路径 - lca到根的路径 - lca的父亲到根的路径(lca的权值要计算).那么查询的时候在这4棵主席树上跑跑就可以了.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 100010;

int n,m,head[maxn],to[maxn * 2],nextt[maxn * 2],tot = 1,a[maxn],fa[maxn][21];
int b[maxn],cnt,num,root[maxn],lastans,deep[maxn];

struct node
{
    int left,right,sum;
}e[maxn * 20];

void add(int x,int y)
{
    to[tot] = y;
    nextt[tot] = head[x];
    head[x] = tot++;
}

void update(int l,int r,int x,int &y,int v)
{
    e[y = ++num] = e[x];
    e[y].sum++;
    if (l == r)
        return;
    int mid = (l + r) >> 1;
    if (v <= mid)
        update(l,mid,e[x].left,e[y].left,v);
    else
        update(mid + 1,r,e[x].right,e[y].right,v);
}

void dfs(int u,int faa,int dep)
{
    fa[u][0] = faa;
    deep[u] = dep;
    int pos = lower_bound(b + 1,b + 1 + cnt,a[u]) - b;
    update(1,cnt,root[faa],root[u],pos);
    for (int i = head[u];i;i = nextt[i])
    {
        int v = to[i];
        if (v == faa)
            continue;
        dfs(v,u,dep + 1);
    }
}

int lca(int x,int y)
{
    if (x == y)
        return x;
    if (deep[x] < deep[y])
        swap(x,y);
    for (int j = 19; j >= 0; j--)
        if (deep[fa[x][j]] >= deep[y])
            x = fa[x][j];
    if (x == y)
        return x;
    for (int j = 19; j >= 0; j--)
        if (fa[x][j] != fa[y][j])
            x = fa[x][j],y = fa[y][j];
    return fa[x][0];
}

int query(int l,int r,int a,int b,int c,int d,int k)
{
    if (l == r)
        return l;
    int mid = (l + r) >> 1;
    int temp = e[e[a].left].sum + e[e[b].left].sum - e[e[c].left].sum - e[e[d].left].sum;
    if (k <= temp)
        return query(l,mid,e[a].left,e[b].left,e[c].left,e[d].left,k);
    else
        return query(mid + 1,r,e[a].right,e[b].right,e[c].right,e[d].right,k - temp);
}

int main()
{
    scanf("%d%d",&n,&m);
    for (int i = 1; i <= n; i++)
        scanf("%d",&a[i]);
    memcpy(b,a,sizeof(a));
    sort(b + 1,b + 1 + n);
    cnt = unique(b + 1,b + 1 + n) - b - 1;
    for (int i = 1; i < n; i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    dfs(1,0,1);
    for (int j = 1; j <= 19; j++)
        for (int i = 1; i <= n; i++)
            fa[i][j] = fa[fa[i][j - 1]][j - 1];
    for (int i = 1; i <= m; i++)
    {
        int u,v,k;
        scanf("%d%d%d",&u,&v,&k);
        u ^= lastans;
        int LCA = lca(u,v);
        lastans = b[query(1,cnt,root[u],root[v],root[LCA],root[fa[LCA][0]],k)];
        if (i != m)
            printf("%d\n",lastans);
        else
            printf("%d",lastans);
    }

    return 0;
}

 

 

posted @ 2018-02-09 16:40  zbtrs  阅读(197)  评论(0编辑  收藏  举报