SPOJ - COT Count on a tree 主席树+树上倍增LCA+rmq+离散化

题目链接:点击查看

题意:一个树,给出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;
}

猜你喜欢

转载自blog.csdn.net/mmk27_word/article/details/89116564