bzoj2588 Spoj 10628. Count on a tree

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




HINT:

N,M<=100000

暴力自重。。。

正解:树上主席树

利用树上前缀和的思想来进行主席树的操作,用dfs序存储每个结点的信息,然后就是道主席树版子题了。。

//It is made by wfj_2048~
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define inf 1<<30
#define il inline
#define RG register
#define ll long long
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)

using namespace std;

struct edge{ int nt,to; }g[200010];

int head[100010],size[100010],dep[100010],dfn[100010],top[100010],fa[100010],son[100010],a[100010],num[100010],hashh[100010],root[100010],sum[5000010],ls[5000010],rs[5000010],m,n,N,sz,tot,cnt,pre;

il int gi(){
    RG int x=0,q=0; RG char ch=getchar();
    while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); if (ch=='-') q=1,ch=getchar();
    while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q ? -x : x;
}

il void ins(RG int from,RG int to){ g[++N]=(edge){head[from],to},head[from]=N; return; }

il void insert(RG int l,RG int r,RG int x,RG int &y,RG int v){
    y=++sz,sum[y]=sum[x]+1; if (l==r) return; ls[y]=ls[x],rs[y]=rs[x]; RG int mid=(l+r)>>1;
    if (v<=mid) insert(l,mid,ls[x],ls[y],v); else insert(mid+1,r,rs[x],rs[y],v); return;
}

il void dfs1(RG int x,RG int p){
    dfn[x]=++cnt,dep[x]=dep[p]+1,fa[x]=p,size[x]=1; RG int v,mx=0;
    for (RG int i=head[x];i;i=g[i].nt){
	v=g[i].to; if (v==p) continue; dfs1(v,x);
	size[x]+=size[v]; if (size[mx]<size[v]) mx=v;
    }
    son[x]=mx; return;
}

il void dfs2(RG int x,RG int p,RG int anc){
    insert(1,tot,root[dfn[p]],root[dfn[x]],lower_bound(hashh+1,hashh+tot+1,a[x])-hashh);
    top[x]=anc; if (son[x]) dfs2(son[x],x,anc); RG int v;
    for (RG int i=head[x];i;i=g[i].nt){
	v=g[i].to; if (v==p || v==son[x]) continue; dfs2(v,x,v);
    }
    return;
}

il int lca(RG int u,RG int v){
    RG int t; while (top[u]!=top[v]){ if (dep[top[u]]<dep[top[v]]) t=u,u=v,v=t; u=fa[top[u]]; }
    if (dep[u]<dep[v]) return u; else return v;
}

il int query(RG int a,RG int b,RG int k){
    RG int c=lca(a,b),d=fa[c],L=1,R=tot,mid,tmp;
    a=root[dfn[a]],b=root[dfn[b]],c=root[dfn[c]],d=root[dfn[d]];
    while (L<R){
	mid=(L+R)>>1,tmp=sum[ls[a]]+sum[ls[b]]-sum[ls[c]]-sum[ls[d]];
	if (k<=tmp) R=mid,a=ls[a],b=ls[b],c=ls[c],d=ls[d];
	else L=mid+1,k-=tmp,a=rs[a],b=rs[b],c=rs[c],d=rs[d];
    }
    return hashh[L];
}

il void work(){
    n=gi(),m=gi(); for (RG int i=1;i<=n;++i) num[i]=a[i]=gi();
    for (RG int i=1;i<n;++i){ RG int u=gi(),v=gi(); ins(u,v),ins(v,u); } sort(num+1,num+n+1);
    hashh[++tot]=num[1]; for (RG int i=2;i<=n;++i) if (num[i]!=num[i-1]) hashh[++tot]=num[i];
    dfs1(1,0),dfs2(1,0,1);
    for (RG int i=1;i<=m;++i){
	RG int u=gi(),v=gi(),k=gi(); pre=query(u^pre,v,k);
	printf("%d",pre); if (i!=m) printf("\n");
    }
    return;
}

int main(){
    File("chairtree");
    work();
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值