题目链接: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