Distance on the tree(树上主席树+LCA)

https://nanti.jisuanke.com/t/38229

题意:求树上两点间的边权小于K的个数

题意:LCA在dfs预处理的时候建主席树,利用前缀和(树上同样满足), 然后这样

	int ans=query(1,n,root[llccaa],root[x],h)+query(1,n,root[llccaa],root[y],h);

求出两点的LCA 就好了,就成树上主席树了 这里用的倍增LCA

注意就是得离散化,

//预处理parent[v][k]:O(nlogn),单次查询:O(logn)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
struct node{
	int l,r;
	int sum;
}T[maxn*50];
struct edge{
	int v,w;
	int next; 
}e[maxn*2];
int head[maxn],size,root[maxn],cnt,rt=1;
int n,m,dep[maxn],f[maxn][25],lg[maxn];
vector<int>v;
void add(int u,int v,int w){
	e[size].v=v;
	e[size].w=w;
	e[size].next=head[u];
	head[u]=size++;	
}
int getid(int x){
	return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
void update(int l,int r,int &x,int y,int pos){
	T[++cnt]=T[y];
	T[cnt].sum++;
	x=cnt;
	if(l==r) return ;
	int mid=(l+r)/2;
	if(pos<=mid) update(l,mid,T[x].l,T[y].l,pos);
	else update(mid+1,r,T[x].r,T[y].r,pos);
}
int query(int l,int r,int L,int R,int k){//小于K的个数 
	if(r<=k) return T[R].sum-T[L].sum;
	int mid=(l+r)/2;
	int ls=T[T[R].l].sum-T[T[L].l].sum;
	if(mid>=k) return query(l,mid,T[L].l,T[R].l,k);
	else return ls+query(mid+1,r,T[L].r,T[R].r,k);
}
void dfs(int u,int fa,int d){
	dep[u]=d;
	f[u][0]=fa; 
	for(int i=head[u];~i;i=e[i].next){
		int v=e[i].v; int w=e[i].w;
		if(v!=fa){
		   update(1,n,root[v],root[u],getid(w));
		   dfs(v,u,d+1);
		} 
	}
}
int lca(int u,int v){
	if(dep[u]<dep[v]) swap(u,v);
	while(dep[u]!=dep[v]){
		int d=dep[u]-dep[v];
		if(lg[d]-1>=0) u=f[u][lg[d]-1];
		else u=f[u][0];
	}
	if(u==v) return u;
	for(int i=lg[dep[v]];i>=0;i--){
		if(f[u][i]!=f[v][i]){
			u=f[u][i];
			v=f[v][i];
		}
	}
	return f[u][0];
}
int init(){
	for(int i=1;i<=n;i++)
	  lg[i]=lg[i-1]+(1<<lg[i-1]==i);
	  
	dfs(rt,0,1); //无向图根节点为1 
	
	for(int j=1;j<=20;j++){
        for(int i=1;i<=n;i++){
            f[i][j]=f[f[i][j-1]][j-1];
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
	int N=n-1;
	memset(head,-1,sizeof(head));
	while(N--){
		int x,y,z; scanf("%d%d%d",&x,&y,&z);
		add(x,y,z); add(y,x,z);
		v.push_back(z);
	}	
	sort(v.begin(),v.end());
	v.erase(unique(v.begin(),v.end()),v.end());
    //离散化后操作的都是下标 
	init();
	while(m--){
		int x,y,k; scanf("%d%d%d",&x,&y,&k);
		int llccaa=lca(x,y);
		int h=upper_bound(v.begin(),v.end(),k)-v.begin();//注意这个二分 
		if(h!=0){
			int ans=query(1,n,root[llccaa],root[x],h)+query(1,n,root[llccaa],root[y],h);
			printf("%d\n",ans);
		}
		else{
			puts("0");
		}
		
	}
	
	
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章