bzoj 2588 Count on a tree
Posted qt666
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 2588 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
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
8
9
105
7
HINT
HINT:
N,M<=100000
暴力自重。。。
Source
树上的主席树,本来应该自已YY一下的但是没有想出来。。。尴尬。。。
其实还是很简单的。。。
每个节点以其父亲节点为历史版本建主席树,在dfs的时候insert;
那么每个点的线段树相当于是维护了从根节点到该节点路径上的点。。。
对于树上两点l,r路径上的第k大,那么要找出l,r的LCA,由于这个LCA也是需要被考虑的,所以还要求LCA的爸爸;
所以每次相当于是 s[ls[l]]+s[ls[r]]-s[ls[lca]]-s[ls[fa[lca]];
这个东西把图画出来,其实就是一个树上的前缀和思想。。。
附上代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int N=100050; 7 int gi() 8 { 9 int x=0,flag=1; 10 char ch=getchar(); 11 while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘) flag=-1;ch=getchar();} 12 while(ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar(); 13 return x*flag; 14 } 15 int hash[N],num[N],v[N],s[N*30],sz,root[N],ls[N*30],rs[N*30]; 16 int dfn[N],head[N*2],nxt[N*2],to[N*2],son[N],dep[N],size[N],fa[N],top[N]; 17 int id[N],tt,cnt,tot,n,m,last; 18 int find(int x) 19 { 20 int l=1,r=tot; 21 while(l<=r) 22 { 23 int mid=(l+r)>>1; 24 if(hash[mid]<x) l=mid+1; 25 else r=mid-1; 26 } 27 return l; 28 } 29 void insert(int l,int r,int x,int &y,int k) 30 { 31 y=++sz; 32 s[y]=s[x]+1;ls[y]=ls[x],rs[y]=rs[x]; 33 if(l==r) return; 34 int mid=(l+r)>>1; 35 if(k<=mid) insert(l,mid,ls[x],ls[y],k); 36 else insert(mid+1,r,rs[x],rs[y],k); 37 } 38 int query(int l,int r,int a,int b,int c,int d,int k) 39 { 40 if(l==r) return hash[l]; 41 int mid=(l+r)>>1; 42 if(s[ls[a]]+s[ls[b]]-s[ls[c]]-s[ls[d]]>=k) 43 return query(l,mid,ls[a],ls[b],ls[c],ls[d],k); 44 else return query(mid+1,r,rs[a],rs[b],rs[c],rs[d],k-(s[ls[a]]+s[ls[b]]-s[ls[c]]-s[ls[d]])); 45 } 46 void dfs1(int x,int f) 47 { 48 dep[x]=dep[f]+1;size[x]=1; 49 insert(1,tot,root[f],root[x],find(v[x])); 50 for(int i=head[x]; i; i=nxt[i]) 51 { 52 int y=to[i]; 53 if(y!=f) 54 { 55 dfs1(y,x); 56 fa[y]=x;size[x]+=size[y]; 57 if(size[y]>size[son[x]]) son[x]=y; 58 } 59 } 60 } 61 void dfs2(int x,int f) 62 { 63 dfn[x]=++tt,top[x]=f; 64 if(son[x]) dfs2(son[x],f); 65 for(int i=head[x]; i; i=nxt[i]) 66 { 67 int y=to[i]; 68 if(y!=fa[x]&&y!=son[x]) dfs2(y,y); 69 } 70 } 71 int lca(int x,int y) 72 { 73 while(top[x]!=top[y]) 74 { 75 if(dep[top[x]]<dep[top[y]]) swap(x,y); 76 x=fa[top[x]]; 77 } 78 if(dep[x]<dep[y]) swap(x,y); 79 return y; 80 } 81 void lnk(int x,int y) 82 { 83 to[++cnt]=y,nxt[cnt]=head[x],head[x]=cnt; 84 to[++cnt]=x,nxt[cnt]=head[y],head[y]=cnt; 85 } 86 int main() 87 { 88 n=gi(),m=gi(); 89 for(int i=1; i<=n; i++) v[i]=gi(),num[i]=v[i]; 90 sort(num+1,num+1+n); 91 hash[++tot]=num[1]; 92 for(int i=2; i<=n; i++) 93 if(num[i]!=num[i-1]) 94 hash[++tot]=num[i]; 95 int x,y,k; 96 for(int i=1; i<n; i++) x=gi(),y=gi(),lnk(x,y); 97 dfs1(1,0);dfs2(1,1); 98 for(int i=1; i<=m; i++) 99 { 100 x=gi();y=gi();k=gi();x^=last; 101 int a=root[x],b=root[y],c=root[lca(x,y)],d=root[fa[lca(x,y)]]; 102 last=query(1,tot,a,b,c,d,k); 103 printf("%d",last);if(i!=m) printf("\n"); 104 } 105 }
以上是关于bzoj 2588 Count on a tree的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ2588 Spoj 10628. Count on a tree
BZOJ 2588: Spoj 10628. Count on a tree