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;
}

 

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