BZOJ2588: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
暴力自重。。。
Solution
emmmLCA求错了然后debug了1h的丢人事迹我是不会说的
一开始看到这个题以为是点分,然后发现没法做。
现在做主席树的时候做到这个题了
就想在DFS序上搞事情……就像链剖一样……然后GG了
偷看了一眼题解的第一行发现用Root[i]表示路径[1,i]情况
然后就没什么思维难度了……
对于路径[u,v]的离散化后的值域情况
我们可以用segt[v]+segt[u]-segt[lca]-segt[father[lca]]来计算
然后就是求第k大的模板了
建树的时候有点小技巧(见代码)
一开始看到这个题以为是点分,然后发现没法做。
现在做主席树的时候做到这个题了
就想在DFS序上搞事情……就像链剖一样……然后GG了
偷看了一眼题解的第一行发现用Root[i]表示路径[1,i]情况
然后就没什么思维难度了……
对于路径[u,v]的离散化后的值域情况
我们可以用segt[v]+segt[u]-segt[lca]-segt[father[lca]]来计算
然后就是求第k大的模板了
建树的时候有点小技巧(见代码)
Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #define N (100000+100) 6 using namespace std; 7 struct node{int sum,lson,rson;}Segt[N*40]; 8 struct node1{int to,next;}edge[N*2]; 9 int a[N],b[N],n,m,Root[N],segt_num,u,v,x,y,k,num,lastans; 10 int head[N],num_edge,Father[N],f[N][20],Depth[N]; 11 12 void add(int u,int v) 13 { 14 edge[++num_edge].to=v; 15 edge[num_edge].next=head[u]; 16 head[u]=num_edge; 17 } 18 19 int Build(int l,int r) 20 { 21 int node=++segt_num; 22 if (l==r) return node; 23 int mid=(l+r)>>1; 24 Segt[node].lson=Build(l,mid); 25 Segt[node].rson=Build(mid+1,r); 26 return node; 27 } 28 29 int Update(int pre,int l,int r,int x) 30 { 31 int node=++segt_num; 32 Segt[node].sum=Segt[pre].sum+1; 33 Segt[node].lson=Segt[pre].lson; 34 Segt[node].rson=Segt[pre].rson; 35 if (l==r) return node; 36 int mid=(l+r)>>1; 37 if (x<=mid) Segt[node].lson=Update(Segt[node].lson,l,mid,x); 38 else Segt[node].rson=Update(Segt[node].rson,mid+1,r,x); 39 return node; 40 } 41 42 void Dfs1(int x) 43 { 44 Depth[x]=Depth[Father[x]]+1; 45 for (int i=head[x];i;i=edge[i].next) 46 if (edge[i].to!=Father[x]) 47 { 48 Father[edge[i].to]=f[edge[i].to][0]=x; 49 Dfs1(edge[i].to); 50 } 51 } 52 53 void Dfs2(int x) 54 { 55 int t=lower_bound(b+1,b+num+1,a[x])-b; 56 Root[x]=Update(Root[Father[x]],1,num,t);//因为这里父亲的主席树已经建立好了,所以这个点的主席树就可以建立了 57 for (int i=head[x];i;i=edge[i].next) 58 if (edge[i].to!=Father[x]) 59 Dfs2(edge[i].to); 60 } 61 62 int Query(int u,int v,int lca,int flca,int l,int r,int k) 63 { 64 if (l==r) return b[l]; 65 int mid=(l+r)>>1,x=Segt[Segt[u].lson].sum+Segt[Segt[v].lson].sum-Segt[Segt[lca].lson].sum-Segt[Segt[flca].lson].sum; 66 if (k<=x) return Query(Segt[u].lson,Segt[v].lson,Segt[lca].lson,Segt[flca].lson,l,mid,k); 67 else return Query(Segt[u].rson,Segt[v].rson,Segt[lca].rson,Segt[flca].rson,mid+1,r,k-x); 68 } 69 70 int LCA(int x,int y) 71 { 72 if (Depth[x]<Depth[y]) swap(x,y); 73 for (int i=18;i>=0;--i) 74 if (Depth[f[x][i]]>=Depth[y]) 75 x=f[x][i]; 76 if (x==y) return y; 77 for (int i=18;i>=0;--i) 78 if (f[x][i]!=f[y][i]) 79 x=f[x][i],y=f[y][i]; 80 return Father[x]; 81 } 82 83 int main() 84 { 85 scanf("%d%d",&n,&m); 86 for (int i=1;i<=n;++i) 87 scanf("%d",&a[i]),b[i]=a[i]; 88 sort(b+1,b+n+1); 89 num=unique(b+1,b+n+1)-b-1; 90 Root[0]=Build(1,num);//多一个0点方便处理,作为1的父亲 91 add(0,1); add(1,0); 92 for (int i=1;i<=n-1;++i) 93 { 94 scanf("%d%d",&u,&v); 95 add(u,v); add(v,u); 96 } 97 Dfs1(0);//以1为根建树 98 for (int i=1;i<=18;++i) 99 for (int j=1;j<=n;++j) 100 f[j][i]=f[f[j][i-1]][i-1]; 101 Dfs2(1);//建立主席树 102 for (int i=1;i<=m;++i) 103 { 104 scanf("%d%d%d",&x,&y,&k); 105 x^=lastans; 106 int lca=LCA(x,y); 107 printf("%d\n",lastans=Query(Root[x],Root[y],Root[lca],Root[Father[lca]],1,num,k)); 108 } 109 }