SPOJ COT Count on a tree(主席树+倍增lca)

思路:这个题其实就是树上的第k小,主席树的本质还是类似于前缀和一样的结构,所以是完全相同的,所以我们在树上也可以用同样的方法,我们对于每一个节点进行建树,然后和普通的树上相同,ab之间的距离是等于

root[a]+root[b]-root[lca[a,b]]-root[fa[lca[a,b]]]

代码:

复制代码
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+7;
const int POW=18;
int num[maxn],sa[maxn];
int ls[maxn40],rs[maxn40];
int sum[maxn*40];
int root[maxn];
vector<int>mp[maxn];
int dis[maxn];
int p[maxn][POW];
int cnt;
int f[maxn];

void build(int l,int r,int &rt)
{
rt=++cnt;
sum[rt]=0;
if(l>=r)return ;
int mid=(l+r)>>1;
build(l,mid,ls[rt]);
build(mid+1,r,rs[rt]);
}
void update(int last,int p,int l,int r,int &rt)
{
rt=++cnt;
ls[rt]=ls[last];
rs[rt]=rs[last];
sum[rt]=sum[last]+1;
if(l>=r)return ;
int mid=(l+r)>>1;
if(p<=mid)update(ls[last],p,l,mid,ls[rt]);
else update(rs[last],p,mid+1,r,rs[rt]);
}
int query(int lrt,int rrt,int lcart,int lcafrt,int l,int r,int k)
{
if(l>=r)return l;
int mid=(l+r)>>1;
int ans=sum[ls[rrt]]+sum[ls[lrt]]-sum[ls[lcart]]-sum[ls[lcafrt]];
if(k<=ans)
return query(ls[lrt],ls[rrt],ls[lcart],ls[lcafrt],l,mid,k);
else
return query(rs[lrt],rs[rrt],rs[lcart],rs[lcafrt],mid+1,r,k-ans);
}
void dfs(int u,int fa,int tot)
{
f[u]=fa;
dis[u]=dis[fa]+1;
p[u][0]=fa;
for(int i=1;i<POW;i++)
p[u][i]=p[p[u][i-1]][i-1];
update(root[fa],num[u],1,tot,root[u]);
for(int i=0;i<mp[u].size();i++){
int v=mp[u][i];
if(v==fa)continue;
dfs(v,u,tot);
}
}
int lca(int a,int b)
{
if(dis[a]>dis[b])swap(a,b);
if(dis[a]<dis[b]){
int del=dis[b]-dis[a];
for(int i=0;i<POW;i++)
if(del&(1<<i))b=p[b][i];
}
if(a!=b){
for(int i=POW-1;i>=0;i--){
if(p[a][i]!=p[b][i]){
a=p[a][i];b=p[b][i];
}
}
a=p[a][0];b=p[b][0];
}
return a;
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m)){
for(int i=0;i<n;i++)mp[i].clear();
memset(dis,0,sizeof(dis));
memset(p,0,sizeof(p));
memset(f,0,sizeof(f));
for(int i=1;i<=n;i++){
scanf("%d",&num[i]);
sa[i]=num[i];
}
cnt=0;
sort(sa+1,sa+1+n);
int tot=unique(sa+1,sa+1+n)-sa-1;
for(int i=1;i<=n;i++){
num[i]=lower_bound(sa+1,sa+tot+1,num[i])-sa;
}
int a,b,c;
for(int i=1;i<n;i++){
scanf("%d%d",&a,&b);
mp[a].push_back(b);
mp[b].push_back(a);
}
build(1,tot,root[0]);
dfs(1,0,tot);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&a,&b,&c);
int t=lca(a,b);
int id=query(root[a],root[b],root[t],root[f[t]],1,tot,c);
printf("%d\n",sa[id]);
}
}
return 0;
}
/
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
2 5 2
2 5 3
2 5 4
7 8 2
/

原文地址:http://blog.51cto.com/13878968/2147579

时间: 2024-10-12 16:00:14

SPOJ COT Count on a tree(主席树+倍增lca)的相关文章

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

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 主席树+倍增LCA

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

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

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

【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 10628 Count on a tree(Tarjan离线LCA+主席树求树上第K小)

COT - Count on a tree #tree 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 from node u 

spoj COT - Count on a tree (树上第K小 LCA+主席树)

链接: https://www.spoj.com/problems/COT/en/ 思路: 首先看到求两点之前的第k小很容易想到用主席树去写,但是主席树处理的是线性结构,而这道题要求的是树形结构,我们可以用dfs跑出所有点离根的距离-dep[i](根为1,dep[1]也为1)在dfs的过程 中,我们对每一个节点建一棵线段树,那么[a,b]就是:root[a] + root[b] - root[lca(a,b)] - root[f[lca(a,b)]]; (因为a-b的路径上的权值还要算上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