2588. Count on a tree【主席树+LCA】

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

暴力自重。。。

emmmLCA求错了然后debug了1h的丢人事迹我是不会说的
一开始看到这个题以为是点分,然后发现没法做。
现在做主席树的时候做到这个题了
就想在DFS序上搞事情……就像链剖一样……然后GG了
偷看了一眼题解的第一行发现用Root[i]表示路径[1,i]情况
然后就没什么思维难度了……
对于路径[u,v]的离散化后的值域情况
我们可以用segt[v]+segt[u]-segt[lca]-segt[father[lca]]来计算
然后就是求第k大的模板了
建树的时候有点小技巧(见代码)

  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 }

原文地址:https://www.cnblogs.com/refun/p/8685692.html

时间: 2024-10-01 07:13:54

2588. Count on a tree【主席树+LCA】的相关文章

BZOJ 2588: Spoj 10628. Count on a tree 主席树+lca

2588: 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),表示一组询问.

BZOJ 2588 Count on a tree 主席树+倍增LCA

题目大意:给定一棵树,每个节点有权值,询问两个节点路径上的权值第k小 这题很卡时间... 树链剖分+二分+树套树的O(nlog^4n)做法可以去死了 没有修改操作,树链剖分+二分+划分树O(nlog^3n),还是死了 我怒了,裸学了一发可持久化线段树(不看任何代码OTZ,我是怎么做到的0.0),二分+主席树,O(nlog^2n),居然还是死了! 最后发现我SB了,完全没有必要二分,直接把4个参全传下去就行了,O(nlogn) 首先我们对于每个节点维护这个节点到根的权值线段树 然后对于每个询问(x

【BZOJ2588】Spoj 10628. Count on a tree 主席树+LCA

[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),表示一组

spoj COT - Count on a tree(主席树 +lca,树上第K大)

您将获得一个包含N个节点的树.树节点的编号从1到?.每个节点都有一个整数权重. 我们会要求您执行以下操作: uvk:询问从节点u到节点v的路径上的第k个最小权重 输入 在第一行中有两个整数?和中号.(N,M <= 100000) 在第二行中有N个整数.第i个整数表示第i个节点的权重. 在接下来的N-1行中,每行包含两个整数u v,它描述了一个边(u,v). 在接下来的M行中,每行包含三个整数u v k,这意味着要求从节点u到节点v的路径上的第k个最小权重的操作. 解题思路: 首先对于求第K小的问

【BZOJ-2588】Count on a tree 主席树 + 倍增

2588: Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MBSubmit: 3749  Solved: 873[Submit][Status][Discuss] Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Input 第一行

spoj cot: Count on a tree 主席树

10628. Count on a tree Problem code: COT You are given a tree with N nodes.The tree nodes are numbered from 1 to N.Each node has an integer weight. We will ask you to perform the following operation: u v k : ask for the kth minimum weight on the path

P2633 Count on a tree(主席树)

题目描述 给定一棵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:

Count on a tree SPOJ 主席树+LCA(树链剖分实现)(两种存图方式)

Count on a tree SPOJ 主席树+LCA(树链剖分实现)(两种存图方式) 题外话,这是我第40篇随笔,纪念一下.<( ̄︶ ̄)[GO!] 题意 是说有棵树,每个节点上都有一个值,然后让你求从一个节点到另一个节点的最短路上第k小的值是多少. 解题思路 看到这个题一想以为是树链剖分+主席树,后来写着写着发现不对,因为树链剖分我们分成了一小段一小段,这些小段不能合并起来求第k小,所以这个想法不对.奈何不会做,查了查题解,需要用LCA(最近公共祖先),然后根据主席树具有区间加减的性质,我们

SPOJ COT Count on a tree(树上主席树 + LCA 求路径第k小)题解

题意:n个点的树,每个点有权值,问你u~v路径第k小的点的权值是? 思路: 树上主席树就是每个点建一棵权值线段树,具体看JQ博客,LCA用倍增logn求出,具体原理看这里 树上主席树我每个点的存的是点u到源点1的权值线段树,那我求点u到v的所有点,显然是 u + v - lca - fa[lca],就是u到1 + v到1 - 多算的lca - 多算的fa[lca].不能减去两个lca不然少一个点了, LCA板子: //LCA int fa[maxn][20]; int dep[maxn]; vo