bzoj2588:Count on a tree(可持久化线段树+Lca)

来源:互联网 发布:照片说话软件 编辑:程序博客网 时间:2024/05/01 05:39

2588: Spoj 10628. Count on a tree

Time Limit: 12Sec  Memory Limit: 128 MB
Submit: 5524  Solved: 1306

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

题目分析:可持久化线段树,一个节点以它的fa的线段树作为历史版本做适当修改。当我们要查u->v的路径第k小时,我们同时在u,v,lca(u,v),fa[lca(u,v)]四棵树上进行二叉查找。

写代码的时候发现与其将空子树指向NULL还不如指向池子的第0位,然后让第0位指向自身。这样Query的时候就可以在0的地方不停地打转,不会爆栈。

没看清输出格式,PE了一发……

CODE:

#include<iostream>#include<string>#include<cstring>#include<cmath>#include<cstdio>#include<cstdlib>#include<stdio.h>#include<algorithm>using namespace std;const int maxn=100100;const int maxl=20;const int oo=1000000001;struct data{int obj;data *Next;} e[maxn<<1];data *head[maxn];int cur=-1;struct Tnode{int num;Tnode *lson,*rson;} tree[(maxn<<2)+maxn*maxl];Tnode *Root[maxn];int Tcur=-1;struct Input{int Time,val,place;} a[maxn];int id[maxn];int temp=0;int fa[maxn][maxl];int dep[maxn];int n,m;void Add(int x,int y){cur++;e[cur].obj=y;e[cur].Next=head[x];head[x]=e+cur;}bool Comp1(Input x,Input y){return x.val<y.val;}bool Comp2(Input x,Input y){return x.Time<y.Time;}Tnode *New_node(){Tcur++;tree[Tcur].lson=tree[Tcur].rson=tree;tree[Tcur].num=0;return tree+Tcur;}void Update(Tnode *root,int L,int R,int x){if ( L==x && x==R ){root->num++;return;}int mid=(L+R)>>1;if (x<=mid){Tnode *y=root->lson;root->lson=New_node();*(root->lson)=*y;Update(root->lson,L,mid,x);}else{Tnode *y=root->rson;root->rson=New_node();*(root->rson)=*y;Update(root->rson,mid+1,R,x);}root->num=root->lson->num+root->rson->num;}void Dfs(int node){Root[node]=New_node();*Root[node]=*Root[ fa[node][0] ];Update(Root[node],1,temp,a[node].place);data *p;for (p=head[node]; p; p=p->Next)if (p->obj!=fa[node][0]){int son=p->obj;fa[son][0]=node;dep[son]=dep[node]+1;Dfs(son);}}void Make_fa(){for (int j=1; j<maxl; j++)for (int i=1; i<=n; i++)fa[i][j]=fa[ fa[i][j-1] ][j-1];}int Lca(int u,int v){if (dep[u]<dep[v]) swap(u,v);for (int j=maxl-1; j>=0; j--)if ( dep[ fa[u][j] ]>=dep[v] )u=fa[u][j];if (u==v) return u;for (int j=maxl-1; j>=0; j--)if (fa[u][j]!=fa[v][j]){u=fa[u][j];v=fa[v][j];}return fa[u][0];}int Query(Tnode *ru,Tnode *rv,Tnode *rw,Tnode *rfw,int L,int R,int k){if (L==R) return L;int left_num=ru->lson->num+rv->lson->num-rw->lson->num-rfw->lson->num;int mid=(L+R)>>1;if (k<=left_num) return Query(ru->lson,rv->lson,rw->lson,rfw->lson,L,mid,k);else return Query(ru->rson,rv->rson,rw->rson,rfw->rson,mid+1,R,k-left_num);}int main(){freopen("c.in","r",stdin);freopen("c.out","w",stdout);scanf("%d%d",&n,&m);for (int i=1; i<=n; i++) scanf("%d",&a[i].val);for (int i=1; i<=n; i++) a[i].Time=i;for (int i=1; i<=n; i++) head[i]=NULL;for (int i=1; i<n; i++){int x,y;scanf("%d%d",&x,&y);Add(x,y);Add(y,x);}a[0].val=-oo;sort(a+1,a+n+1,Comp1);for (int i=1; i<=n; i++){if (a[i-1].val!=a[i].val) temp++;a[i].place=temp;id[temp]=a[i].val;}sort(a+1,a+n+1,Comp2);//for (int i=1; i<=temp; i++) printf("%d ",id[i]);//printf("\n");Root[0]=New_node();fa[1][0]=0;dep[1]=1;Dfs(1);Make_fa();/*for (int j=0; j<maxl; j++){for (int i=1; i<=n; i++) printf("%d ",fa[i][j]);printf("\n");}*/int lastans=0;for (int i=1; i<=m; i++){int u,v,k;scanf("%d%d%d",&u,&v,&k);u=u^lastans;int w=Lca(u,v);//printf("%d\n",w);lastans=Query(Root[u],Root[v],Root[w],Root[ fa[w][0] ],1,temp,k);lastans=id[lastans];printf("%d",lastans);if (i!=m) printf("\n");}return 0;}
0 0