主席树套LCA
题目链接:https://nanti.jisuanke.com/t/38229、
预处理出lca的一套东西,将查询区间[L,R]分成两半,[L,LCA(L,R)],[R,LCA(L,R)] 计算区间内小于等于k的个数即可
主席树记录每一个子节点到初始节点间出现的所有线段长度的个数。
主席树这种东西的话,,,百度学吧。。。我讲不清,我太菜了。。
对于常见的主席树区间查询来说,查询区间[L,R]需要消掉L-1次操作带来的影响,是因为他每个点具有点权,而这道题是点与点之间具有边权,故消除影响只需要消除lca之前的影响。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn=1e5+7;
int b[maxn];
int n,m;
void quchong(int n){
sort(b+1,b+n);
m=unique(b+1,b+n)-b-1;
}
int getid(int x){
return lower_bound(b+1,b+1+m,x)-b;
}
const int maxm=2e5+7;
struct Edge{
int v,w,next;
}edge[maxm];
int head[maxn],top;
void add(int u,int v,int w){
edge[top].v=v;
edge[top].w=w;
edge[top].next=head[u];
head[u]=top++;
}
struct Tree{
int lc,rc;
int sum;
}tree[2061118];
int tot;
int root[2061118];
void init(){
memset(head,-1,sizeof(head));
top=0;
tot=0;
}
void pushup(int k){
tree[k].sum=tree[tree[k].lc].sum+tree[tree[k].rc].sum;
}
int build(int l,int r){
int k=++tot;
if(l==r){
tree[k].sum=0;
return k;
}
int mid=(l+r)>>1;
tree[k].lc=build(l,mid);
tree[k].rc=build(mid+1,r);
pushup(k);
return k;
}
int updata(int now,int l,int r,int x,int val){
int k=++tot;
tree[k]=tree[now];
if(l==r){
++tree[k].sum;
return k;
}
int mid=(l+r)>>1;
if(x<=mid) tree[k].lc=updata(tree[now].lc,l,mid,x,val);
else tree[k].rc=updata(tree[now].rc,mid+1,r,x,val);
pushup(k);
return k;
}
int myfind(int p,int q,int l,int r,int L,int R){
if(l>=L&&r<=R) return tree[p].sum-tree[q].sum;
int mid=(l+r)>>1;
int res=0;
if(L<=mid) res+=myfind(tree[p].lc,tree[q].lc,l,mid,L,R);
if(R>mid) res+=myfind(tree[p].rc,tree[q].rc,mid+1,r,L,R);
return res;
}
int fa[maxn][29];
int mi=17;
int deap[maxn];
//ll dis[maxn];
queue<int> q;
void bfs(int st){
while(!q.empty()) q.pop();
q.push(st);
deap[st]=1;
//dis[st]=0;
root[st]=build(1,m);
int u,v;
ll w;
while(!q.empty()){
u=q.front(); q.pop();
for(int i=head[u];i!=-1;i=edge[i].next){
v=edge[i].v;
w=edge[i].w;
if(deap[v]) continue;
fa[v][0]=u;
deap[v]=deap[u]+1;
//dis[v]=dis[u]+w;
for(int j=1;j<=mi;++j)
fa[v][j]=fa[fa[v][j-1]][j-1];
root[v]=updata(root[u],1,m,getid(w),1);
q.push(v);
}
}
}
int LCA(int x,int y){
if(deap[x]>deap[y]) swap(x,y);
for(int i=mi;i>=0;--i)
if(deap[fa[y][i]]>=deap[x]) y=fa[y][i];
if(x==y) return x;
for(int i=mi;i>=0;--i)
if(fa[y][i]!=fa[x][i]){
x=fa[x][i];
y=fa[y][i];
}
return fa[x][0];
}
int idd(int x){
int l=1,r=m,mid;
while(l<=r){
mid=(l+r)>>1;
if(b[mid]>x) r=mid-1;
else l=mid+1;
}
return r;
}
int main(){
//cout<<(int)(maxn*4+maxn*log2(maxn))<<endl;
init();
int q;
int u,v,w;
scanf("%d%d",&n,&q);
for(int i=1;i<n;++i){
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
b[i]=w;
}
quchong(n);
root[0]=build(1,m);
bfs(1);
while(q--){
scanf("%d%d%d",&u,&v,&w);
int id=idd(w);
if(id==0) printf("0\n");
else{
int fre=LCA(u,v);
int hh=fa[fre][0];
//cout<<fa[fre][0]<<endl;
printf("%d\n",myfind(root[v],root[fre],1,m,1,id)+myfind(root[u],root[fre],1,m,1,id));
}
}
return 0;
}