【GJOI 2023.10.14 T3】 树上询问

树上询问

你有一棵 \(n\) 个节点的树 \(T\) ,回答 \(m\) 个询问,每次询问给你两个整数 \(l,r\) ,问存在多少个整数 \(k\) 使得从 \(l\) 沿着 \(l->r\) 的简单路径走 \(k\) 步恰好到 \(k\)\(n,m\le 10^6\)

解题思路

分析一下式子,可以发现,设 \(LCA(l,r)=z\) ,若 \(k\)\(l->z\) 路径上,有 \(deep_l-deep_k=k\) ,即为 \(deep_l=deep_k+k\) ,即为统计 \(l->z\) 上有多少个节点 \(i\) 满足 \(deep_i+i=deep_l\)
而在 \(z->r\) 路径上时,有 \(deep_k-deep_z+deep_l-deep_z=k\) ,即为 \(deep_k-k=deep_z \times 2 -deep_l\) ,即为统计 \(r->z\) 上有多少个节点 \(i\) 满足 \(deep_i-i=deep_z \times 2 -deep_l\)
以第一种情况为例,将所有询问离线下来,然后从根节点开始遍历一遍树。
途径一个节点 \(i\) 时就把 \(i+deep_i\) 在一个数组中 \(v\) 存下来,每次处理询问时只需在 \(v\) 中找即可。
第二种情况同理,只是 \(deep_i-i\) 可能为负数,需要离散化或开 \(map\)
总时间复杂度 \(O(nlogn)\)

Code

#include<bits/stdc++.h>
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
using namespace std;
struct datay
{
	int x,y,z;
}t[1200005];
int n,m,deep[300005],f[300005][21],v[600005];
map<int,int> v1;
vector<int> a[300005];
vector<datay> d[300005];
void dijah(int x,int y)
{
	f[x][0]=y;
	deep[x]=deep[y]+1;
	for(int i=0;i<a[x].size();i++)
	{
		if(a[x][i]==y)continue;
		dijah(a[x][i],x);
	}
	return;
}
int LCA(int x,int y)
{
	if(deep[x]<deep[y])swap(x,y);
	for(int i=20;i>=0;i--)
	{
		if(deep[f[x][i]]>=deep[y])x=f[x][i];
	}
	if(x==y)return x;
	for(int i=20;i>=0;i--)
	{
		if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
	}
	return f[x][0];
}
bool cmp1(datay q,datay w)
{
	return q.z<w.z;
}
void gaia(int x,int y)
{
	v[x+deep[x]]++;
	v1[deep[x]-x]++;
	for(int i=0;i<a[x].size();i++)
	{
		if(a[x][i]==y)continue;
		gaia(a[x][i],x);
	}
	for(int i=0;i<d[x].size();i++)
	{
		if(d[x][i].z%2==1)d[x][i].x=v[d[x][i].y];
		else d[x][i].x=v1[d[x][i].y];
	}
	v[x+deep[x]]--;
	v1[deep[x]-x]--;
	return;
}
int main()
{
	int x,y,z;
	scanf("%d%d",&n,&m);
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		a[x].push_back(y);
		a[y].push_back(x);
	}
	dijah(1,0);
	for(int i=1;i<=20;i++)
	{
		for(int j=1;j<=n;j++)f[j][i]=f[f[j][i-1]][i-1];
	}
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		z=LCA(x,y);
		t[i*4-3].x=x;
		t[i*4-3].y=deep[x];
		t[i*4-3].z=i*4-3;
		t[i*4-2].x=y;
		t[i*4-2].y=deep[z]-(deep[x]-deep[z]);
		t[i*4-2].z=i*4-2;
		t[i*4-1].x=z;
		t[i*4-1].y=deep[x];
		t[i*4-1].z=i*4-1;
		t[i*4].x=f[z][0];
		t[i*4].y=deep[z]-(deep[x]-deep[z]);
		t[i*4].z=i*4;
	}
	for(int i=1;i<=4*m;i++)d[t[i].x].push_back(t[i]);
	gaia(1,0);
	long long g=0;
	for(int i=0;i<=n;i++)
	{
		for(int j=0;j<d[i].size();j++)t[++g]=d[i][j];
	}
	sort(t+1,t+g+1,cmp1);
	for(int i=1;i<=m;i++)
	{
		printf("%d\n",t[i*4-3].x+t[i*4-2].x-t[i*4-1].x-t[i*4].x);
	}








  return 0;
}
posted @ 2023-10-17 16:22  dijah  阅读(32)  评论(0编辑  收藏  举报