南昌网络赛 Distance on the tree 主席树+LCA

题目链接:https://nanti.jisuanke.com/t/38229
题意:给一个n个节点的树,m个询问,每次询问u到v中不大于k的边有几条
解法:LCA+主席树
网上比较流行的解法是将原树树链剖分后在原树上建主席树,事实上,本题树链剖分的目的是为了求lca,既然是为了求lca,就不需要写较为繁琐的树链剖分,我直接写了tarjan的倍增求lca的方法,然后在树上建主席树。
下一步的问题就是如何实现这个询问了,首先将所有边权离散后,用upper_bound查找第一个小于k的位置,然后问题就转化为区间第k大问题了。主席树就是为了解决这个问题的,那么如何在树上建主席树呢?主席树的insert的本质是插入当前点的后继点,那么树上的如何定义一个点的后继点呢,很自然的想到了父子结点关系,子节点即是父节点的后继点,然后就可以insert子节点来建立主席树了。

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
struct edge
{
    int u,v,w;
}e[maxn<<1];
int n;
int Next[maxn<<1];
int head[maxn<<1];
int dp[maxn][20];
int dep[maxn];
int cnt;
int tot;
void add(int u,int v,int w)
{
    e[cnt].u=u;
    e[cnt].v=v;
    e[cnt].w=w;
    Next[cnt]=head[u];
    head[u]=cnt++;
}
vector<int>vis;
struct Node
{
    int l,r,val;
    Node(){}
    Node(int a,int b,int c)
    {
        l=a;
        r=b;
        val=c;
    }
}node[maxn*50];
int root[maxn];
int arr[maxn];
int gettid(int num)
{
    return lower_bound(vis.begin(),vis.end(),num)-vis.begin()+1;
}
int insert(int num,int l,int r,int val)
{
    int oo=++tot;
    node[oo].l=node[num].l;
    node[oo].r=node[num].r;
    node[oo].val=node[num].val+1;
    if(l==r)return oo;
    int m=(l+r)>>1;
    if(m>=val)
    {
        node[oo].l=insert(node[oo].l,l,m,val);
    }
    else
    {
        node[oo].r=insert(node[oo].r,m+1,r,val);
    }
    return oo;
}
int query(int u,int v,int l,int r,int k)
{
    if(r<=k) return node[v].val-node[u].val;
	int mid=(l+r)/2;
	int ls=node[node[v].l].val-node[node[u].l].val;
	if(mid>=k) return query(node[u].l,node[v].l,l,mid,k);
	else return ls+query(node[u].r,node[v].r,mid+1,r,k);
}
void dfs(int num,int fa)
{
    dep[num]=dep[fa]+1;
    dp[num][0]=fa;
    for(int i=1;(1<<i)<=dep[num];i++)
    {
        dp[num][i]=dp[dp[num][i-1]][i-1];
    }
    for(int i=head[num];i!=-1;i=Next[i])
    {
        int v=e[i].v;
        int w=e[i].w;
        if(v==fa)continue;
        root[v]=insert(root[num],1,vis.size(),gettid(w));
        dfs(v,num);
    }
}
int lca(int a,int b)
{
    if(dep[a]<dep[b])swap(a,b);
    for(int i=19;i>=0;i--)
    {
        if(dep[a]-(1<<i)>=dep[b])a=dp[a][i];
    }
    if(a==b)return a;
    for(int i=19;i>=0;i--)
    {
        if(dp[a][i]!=dp[b][i])
        {
            a=dp[a][i];
            b=dp[b][i];
        }
    }
    return dp[a][0];
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    memset(head,-1,sizeof(head));
    cnt=0;
    tot=0;
    int m;
    cin>>n>>m;
    for(int i=1;i<n;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
        add(b,a,c);
        vis.push_back(c);
    }
    sort(vis.begin(),vis.end());
	vis.erase(unique(vis.begin(),vis.end()),vis.end());
    dfs(1,0);
    while(m--)
    {
		int x,y,k;
		cin>>x>>y>>k;
		int LCA=lca(x,y);
		int h=upper_bound(vis.begin(),vis.end(),k)-vis.begin();
		if(h!=0){
			int ans=query(root[LCA],root[x],1,vis.size(),h)+query(root[LCA],root[y],1,vis.size(),h);
			cout<<ans<<'\n';
		}
		else{
			cout<<"0"<<'\n';
		}
    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值