SPOJ - COT Count on a tree(主席树 LCA)

简介: SPOJ - COT Count on a tree(主席树 LCA)

link

题意:

u v k : 询问从节点 u 到 节点 v 的路径上的第k小的权值

思路:

树上第k小问题,考虑怎么从序列转到树上。

对于一个节点,先将父节点的信息复制过来,再在r o o t [ i ]里插入a [ i ]

这样每个节点维护的信息就是本节点到根节点的信息

求u − > v u->vu−>v信息的时候,用r o o t [ u ] + r o o t [ v ] − r o o t [ l c a ] − r o o t [ f a [ l c a ] ] ,点差分的式子

因为u − > v路径的点是包括l c a的。

代码:

const int maxn=100000+7,mod=1e9+7,inf=0x3f3f3f3f;
int n,m,a[maxn];
vector<int>num;
struct node{
  int l,r,cnt;
}tr[maxn*40];
vector<int>g[maxn];
int dp[maxn][23],dep[maxn],root[maxn],idx,lim;
int get_id(int x){
  return lower_bound(num.begin(), num.end(),x)-num.begin();
}
void insert(int pre,int &now,int l,int r,int pos){
  now=++idx;
  tr[now]=tr[pre];//全部复制
  tr[now].cnt++;//更新
  if(l==r) return ;
  int mid=(l+r)/2;
  if(mid>=pos) insert(tr[pre].l,tr[now].l,l,mid,pos);
  else insert(tr[pre].r,tr[now].r,mid+1,r,pos);
}
int query(int u,int v,int lca,int lca_fa,int l,int r,int k){
  if(l==r) return l;
  int suml=tr[tr[u].l].cnt+tr[tr[v].l].cnt-tr[tr[lca].l].cnt-tr[tr[lca_fa].l].cnt;
  int mid=(l+r)/2;
  if(suml>=k) return query(tr[u].l,tr[v].l,tr[lca].l,tr[lca_fa].l,l,mid,k);
  else return query(tr[u].r,tr[v].r,tr[lca].r,tr[lca_fa].r,mid+1,r,k-suml);
}
void dfs(int u,int fa,int d){
  insert(root[fa],root[u],0,num.size(),get_id(a[u]));//主席树插入
  dep[u]=d;dp[u][0]=fa;
  for(int i=1;i<=lim;i++)
    dp[u][i]=dp[dp[u][i-1]][i-1];
  for(auto t:g[u]){
    if(t==fa) continue;
    dfs(t,u,d+1);
  }
}
int LCA(int x,int y)//求lca
{
  if(dep[x]<dep[y])
    swap(x,y);
  for(int i=lim;i>=0;i--)
    if(dep[x]-dep[y]>=(1<<i))
      x=dp[x][i];
  if(x==y)
    return x;
  for(int i=lim;i>=0;i--)
    if(dp[x][i]!=dp[y][i])
    {
      x=dp[x][i];
      y=dp[y][i];
    }
  return dp[x][0];
}
int main(){
  n=read,m=read;
  lim=log2(n);
  rep(i,1,n) a[i]=read,num.push_back(a[i]);
  sort(num.begin(),num.end());
  num.erase(unique(num.begin(),num.end()),num.end());
  rep(i,1,n-1){
    int u=read,v=read;
    g[u].push_back(v);
    g[v].push_back(u);
  }
  dfs(1,0,0);//
  rep(i,1,m){
    int u=read,v=read,k=read;
    int t=LCA(u,v);
    printf("%d\n",num[query(root[u],root[v],root[t],root[dp[t][0]],0,num.size(),k)]);
  }
  return 0;
}

目录
相关文章
|
算法
The kth great number(小根堆思想,模板题)
The kth great number(小根堆思想,模板题)
48 0
The kth great number(小根堆思想,模板题)
|
人工智能
poj 2299 Ultra-QuickSort 求逆序数 树状数组解法
所谓离散化,我们的了解就是对原数组排序,然后用所在位置的下标代替原数,这样我们就可以把数据范围缩小到1-500000,这个数组是开的下的。
44 0
|
存储 容器
华为机试HJ41:称砝码(深度优先遍历dfs-Depth First Search)
华为机试HJ41:称砝码(深度优先遍历dfs-Depth First Search)
144 0
|
人工智能
POJ 2299 Ultra-QuickSort(树状数组+离散化+求逆序数)
POJ 2299 Ultra-QuickSort(树状数组+离散化+求逆序数)
|
机器学习/深度学习 C++
【PAT甲级 - C++题解】1151 LCA in a Binary Tree
【PAT甲级 - C++题解】1151 LCA in a Binary Tree
73 0
Codeforces1153——D. Serval and Rooted Tree(思维好题+dfs+贪心)
Codeforces1153——D. Serval and Rooted Tree(思维好题+dfs+贪心)
129 0
Codeforces1153——D. Serval and Rooted Tree(思维好题+dfs+贪心)
SP10707 COT2 - Count on a tree II(欧拉序 树上莫队)
SP10707 COT2 - Count on a tree II(欧拉序 树上莫队)
115 0
SP10707 COT2 - Count on a tree II(欧拉序 树上莫队)
UPC Graph (最小生成树 || 并查集+二分)
UPC Graph (最小生成树 || 并查集+二分)
93 0
CF191C——Fools and Roads(树上边差分+LCA)
CF191C——Fools and Roads(树上边差分+LCA)
128 0
AtCoder Beginner Contest 216 D - Pair of Balls (思维建图 拓扑排序判断有向图是否有环)
AtCoder Beginner Contest 216 D - Pair of Balls (思维建图 拓扑排序判断有向图是否有环)
125 0