P2633 Count on a tree

此生再无相见时 提交于 2019-11-28 01:16:28

题目描述

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

输入格式

第一行两个整数N,M。

第二行有N个整数,其中第i个整数表示点i的权值。

后面N-1行每行两个整数(x,y),表示点x到点y有一条边。

最后M行每行两个整数(u,v,k),表示一组询问。

输出格式

M行,表示每个询问的答案。

输入输出样例

输入 #1
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
输出 #1
2
8
9
105
7

说明/提示

HINT:

N,M<=100000

暴力自重。。。

来源:bzoj2588 Spoj10628.

本题数据为洛谷自造数据,使用CYaRon耗时5分钟完成数据制作。

 

主席树乱搞+lca

#include<bits/stdc++.h>
using namespace std;

const int maxn = 100010;

int n,m,root[maxn],size,head[maxn],lastans,f[maxn][20],dep[maxn],cnt,rank[maxn];

struct hash{
    int val,id;
}point[maxn];

struct Tree{
    int ls,rs,sum;
}tree[maxn*40];

bool cmp(const hash& a,const hash& b){
    return a.val<b.val;
}

struct edge{
    int v,nex;
}e[maxn<<1];

void adde(int u,int v){
    e[size].v=v;e[size].nex=head[u];head[u]=size++;
}

void updata(int &rt,int l,int r,int v){
    tree[++cnt]=tree[rt];
    rt=cnt;
    tree[rt].sum++;
    if(l==r) return;
    int mid=(l+r)>>1;
    if(mid>=v) updata(tree[rt].ls,l,mid,v);
    else updata(tree[rt].rs,mid+1,r,v);
}

void dfs(int u,int fa){
    root[u]=root[fa];
    updata(root[u],1,n,rank[u]);
    f[u][0]=fa;
    dep[u]=dep[fa]+1;
    for(int i=1;i<=18;i++) f[u][i]=f[f[u][i-1]][i-1];
    for(int i=head[u];~i;i=e[i].nex){
        int v=e[i].v;
        if(v==fa) continue;
        dfs(v,u);
    }
}

int query(int i,int j,int lca,int lcaf,int l,int r,int k){
    if(l==r) return l;
    int d = tree[tree[i].ls].sum+tree[tree[j].ls].sum-tree[tree[lca].ls].sum-tree[tree[lcaf].ls].sum;
    int mid=(l+r)>>1;
    if(d>=k) return query(tree[i].ls,tree[j].ls,tree[lca].ls,tree[lcaf].ls,l,mid,k);
    else return query(tree[i].rs,tree[j].rs,tree[lca].rs,tree[lcaf].rs,mid+1,r,k-d);
}

int Lca(int u,int v){
    if(dep[u]<dep[v]) swap(u,v);
    for(int i=18;i>=0;i--) if(dep[f[u][i]]>=dep[v]) u=f[u][i];
    if(u==v) return v;
    for(int i=18;i>=0;i--)if(f[u][i]!=f[v][i]){
        u=f[u][i];v=f[v][i];
    }
    return f[u][0];
}

int query_(int u,int v,int k){
    int lca=Lca(u,v);
    return point[query(root[u],root[v],root[lca],root[f[lca][0]],1,n,k)].val;
}

int main(){
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&point[i].val),point[i].id=i;
    sort(point+1,point+1+n,cmp);
    for(int i=1;i<=n;i++) rank[point[i].id]=i;
    for(int i=1;i<n;i++){
        int u,v;scanf("%d%d",&u,&v);
        adde(u,v);adde(v,u);
    }
    dfs(1,0);
    for(int i=1;i<=m;i++){
        int u,v,k;
        scanf("%d%d%d",&u,&v,&k);
        lastans=query_(u^lastans,v,k);
        printf("%d\n",lastans);
    }
    return 0;
}
View Code

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!