题目链接:点击查看
题意:一个树,给出n个点的高度,求两点路径上第k小的高度
题解1:主席树+倍增找LCA
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct node
{
int l,r;
int val;
}tree[N*22];
vector<int> v[N];
int val[N];
int n,q,deep[N];
int root[N],cnt;
int dp[N][22];
int build(int l,int r,int pre)
{
int cur=++cnt;
tree[cur]=tree[pre];
if(l==r)return cur;
int mid=(r+l)>>1;
tree[cur].l=build(l,mid,tree[pre].l);
tree[cur].r=build(mid+1,r,tree[pre].r);
return cur;
}
int update(int pos,int l,int r,int pre)
{
int cur=++cnt;
tree[cur]=tree[pre];
tree[cur].val++;
if(l==r) return cur;
int mid=(r+l)>>1;
if(pos<=mid) tree[cur].l=update(pos,l,mid,tree[pre].l);
else tree[cur].r=update(pos,mid+1,r,tree[pre].r);
return cur;
}
void dfs(int u,int fa)
{
deep[u]=deep[fa]+1;
root[u]=update(val[u],1,100000,root[fa]);
dp[u][0]=fa;
for(int i=1;i<=20;i++)
{
if(dp[u][i-1])
dp[u][i]=dp[dp[u][i-1]][i-1];
else
break;
}
for(int i=0;i<v[u].size();i++)
{
int to=v[u][i];
if(to==fa) continue;
dfs(to,u);
}
}
int get_lca(int x,int y)
{
if(deep[x]<deep[y]) swap(x,y);
int tmp=deep[x]-deep[y];
for(int i=0;i<=20;i++)
if(tmp&(1<<i))
x=dp[x][i];
if(x==y) return x;
for(int i=20;i>=0;i--)
{
if(dp[x][i]!=dp[y][i])
{
x=dp[x][i];
y=dp[y][i];
}
}
return dp[x][0];
}
int query(int l,int r,int x,int y,int z,int w,int val)
{
if(l==r) return l;
int mid=(r+l)>>1;
if(tree[tree[x].l].val+tree[tree[y].l].val-tree[tree[z].l].val-tree[tree[w].l].val>=val) return query(l,mid,tree[x].l,tree[y].l,tree[z].l,tree[w].l,val);
else return query(mid+1,r,tree[x].r,tree[y].r,tree[z].r,tree[w].r,val-(tree[tree[x].l].val+tree[tree[y].l].val-tree[tree[z].l].val-tree[tree[w].l].val));
}
void init()
{
for(int i=1;i<=n;i++)
{
v[i].clear();
for(int j=0;j<=20;j++)
dp[i][j]=0;
}
}
int rak[N],va[N];
int cmp(int x,int y)
{
return va[x]<va[y];
}
int main()
{
while(~scanf("%d%d",&n,&q))
{
// init();
for(int i=1;i<=n;i++) scanf("%d",&va[i]);
for(int i=1;i<=n;i++) rak[i]=i;
sort(rak+1,rak+1+n,cmp);
for(int i=1;i<=n;i++) val[rak[i]]=i;
int x,y;
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
v[x].push_back(y);
v[y].push_back(x);
}
cnt=0;
root[0]=build(1,100000,0);
dfs(1,0);
int fa,tmp,k;
while(q--)
{
scanf("%d%d%d",&x,&y,&k);
fa=get_lca(x,y);
printf("%d\n",va[rak[query(1,100000,root[x],root[y],root[fa],root[dp[fa][0]],k)]]);
}
}
return 0;
}
题解2:应用rmq求,需要开两倍空间,按照dfs递归寻找的过程,给出一个序列,找两个的LCA时,即两点之间编号最小的
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct node
{
int l,r;
int val;
}tree[N*22];
vector<int> v[N];
int val[N];
int n,q,deep[N];
int root[N],cnt;
int dp[N*2][22],p[N],f[N],id,ip;
int build(int l,int r,int pre)
{
int cur=++cnt;
tree[cur]=tree[pre];
if(l==r)return cur;
int mid=(r+l)>>1;
tree[cur].l=build(l,mid,tree[pre].l);
tree[cur].r=build(mid+1,r,tree[pre].r);
return cur;
}
int update(int pos,int l,int r,int pre)
{
int cur=++cnt;
tree[cur]=tree[pre];
tree[cur].val++;
if(l==r) return cur;
int mid=(r+l)>>1;
if(pos<=mid) tree[cur].l=update(pos,l,mid,tree[pre].l);
else tree[cur].r=update(pos,mid+1,r,tree[pre].r);
return cur;
}
int pre[N];
void dfs(int u,int fa)
{
int cur=++id;
dp[++ip][0]=cur;
p[u]=ip;
f[cur]=u;
deep[u]=deep[fa]+1;
root[u]=update(val[u],1,100000,root[fa]);
pre[u]=fa;
for(int i=0;i<v[u].size();i++)
{
int to=v[u][i];
if(to==fa) continue;
dfs(to,u);
dp[++ip][0]=cur;
}
}
void init_rmq()
{
for(int j=1;j<=20;j++)
for(int i=1;i+(1<<j)-1<=ip;i++)
dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
int get_lca(int x,int y)
{
if(p[x]>p[y]) swap(x,y);
int l=p[x],r=p[y];
int mm=floor(log(1.0*r-l+1)/log(2.0));
return f[min(dp[l][mm],dp[r-(1<<mm)+1][mm])];
}
int query(int l,int r,int x,int y,int z,int w,int val)
{
if(l==r) return l;
int mid=(r+l)>>1;
if(tree[tree[x].l].val+tree[tree[y].l].val-tree[tree[z].l].val-
tree[tree[w].l].val>=val) return
query(l,mid,tree[x].l,tree[y].l,tree[z].l,tree[w].l,val);
else return query(mid+1,r,tree[x].r,tree[y].r,tree[z].r,tree[w].r,val-(tree[tree[x].l].val+tree[tree[y].l].val-tree[tree[z].l].val-tree[tree[w].l].val));
}
void init()
{
for(int i=1;i<=n;i++)
{
v[i].clear();
}
}
int rak[N],va[N];
int cmp(int x,int y)
{
return va[x]<va[y];
}
int main()
{
while(~scanf("%d%d",&n,&q))
{
init();
for(int i=1;i<=n;i++) scanf("%d",&va[i]);
for(int i=1;i<=n;i++) rak[i]=i;
sort(rak+1,rak+1+n,cmp);
for(int i=1;i<=n;i++) val[rak[i]]=i;
int x,y;
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
v[x].push_back(y);
v[y].push_back(x);
}
cnt=0;
id=0;
ip=0;
root[0]=build(1,100000,0);
dfs(1,0);
init_rmq();
int fa,tmp,k;
while(q--)
{
scanf("%d%d%d",&x,&y,&k);
fa=get_lca(x,y);
printf("%d\n",va[rak[query(1,100000,root[x],root[y],root[fa],root[pre[fa]],k)]]);
}
}
return 0;
}
题解3:直接判lca在不在查询区间内
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct node
{
int l,r;
int val;
}tree[N*22];
vector<int> v[N];
int val[N];
int n,q,deep[N];
int root[N],cnt;
int dp[N*2][22],p[N],f[N],id,ip;
int build(int l,int r,int pre)
{
int cur=++cnt;
tree[cur]=tree[pre];
if(l==r)return cur;
int mid=(r+l)>>1;
tree[cur].l=build(l,mid,tree[pre].l);
tree[cur].r=build(mid+1,r,tree[pre].r);
return cur;
}
int update(int pos,int l,int r,int pre)
{
int cur=++cnt;
tree[cur]=tree[pre];
tree[cur].val++;
if(l==r) return cur;
int mid=(r+l)>>1;
if(pos<=mid) tree[cur].l=update(pos,l,mid,tree[pre].l);
else tree[cur].r=update(pos,mid+1,r,tree[pre].r);
return cur;
}
int pre[N];
void dfs(int u,int fa)
{
int cur=++id;
dp[++ip][0]=cur;
p[u]=ip;
f[cur]=u;
deep[u]=deep[fa]+1;
root[u]=update(val[u],1,100000,root[fa]);
pre[u]=fa;
for(int i=0;i<v[u].size();i++)
{
int to=v[u][i];
if(to==fa) continue;
dfs(to,u);
dp[++ip][0]=cur;
}
}
void init_rmq()
{
for(int j=1;j<=20;j++)
for(int i=1;i+(1<<j)-1<=ip;i++)
dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
int get_lca(int x,int y)
{
if(p[x]>p[y]) swap(x,y);
int l=p[x],r=p[y];
int mm=floor(log(1.0*r-l+1)/log(2.0));
return f[min(dp[l][mm],dp[r-(1<<mm)+1][mm])];
}
int query(int l,int r,int x,int y,int z,int lca,int val)
{
if(l==r) return l;
int mid=(r+l)>>1;
if(tree[tree[x].l].val+tree[tree[y].l].val-tree[tree[z].l].val*2+(lca>=l&&lca<=mid)>=val) return query(l,mid,tree[x].l,tree[y].l,tree[z].l,lca,val);
else return query(mid+1,r,tree[x].r,tree[y].r,tree[z].r,lca,val-(tree[tree[x].l].val+tree[tree[y].l].val-tree[tree[z].l].val*2+(lca>=l&&lca<=mid)));
}
void init()
{
for(int i=1;i<=n;i++)
{
v[i].clear();
}
}
int rak[N],va[N];
int cmp(int x,int y)
{
return va[x]<va[y];
}
int main()
{
while(~scanf("%d%d",&n,&q))
{
init();
for(int i=1;i<=n;i++) scanf("%d",&va[i]);
for(int i=1;i<=n;i++) rak[i]=i;
sort(rak+1,rak+1+n,cmp);
for(int i=1;i<=n;i++) val[rak[i]]=i;
int x,y;
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
v[x].push_back(y);
v[y].push_back(x);
}
cnt=0;
id=0;
ip=0;
root[0]=build(1,100000,0);
dfs(1,0);
init_rmq();
int fa,tmp,k;
while(q--)
{
scanf("%d%d%d",&x,&y,&k);
fa=get_lca(x,y);
printf("%d\n",va[rak[query(1,100000,root[x],root[y],root[fa],val[fa],k)]]);
}
}
return 0;
}