【GJOI 2023.10.14 T3】 树上询问

树上询问

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

解题思路

分析一下式子,可以发现,设 LCA(l,r)=z ,若 kl>z 路径上,有 deepldeepk=k ,即为 deepl=deepk+k ,即为统计 l>z 上有多少个节点 i 满足 deepi+i=deepl
而在 z>r 路径上时,有 deepkdeepz+deepldeepz=k ,即为 deepkk=deepz×2deepl ,即为统计 r>z 上有多少个节点 i 满足 deepii=deepz×2deepl
以第一种情况为例,将所有询问离线下来,然后从根节点开始遍历一遍树。
途径一个节点 i 时就把 i+deepi 在一个数组中 v 存下来,每次处理询问时只需在 v 中找即可。
第二种情况同理,只是 deepii 可能为负数,需要离散化或开 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 @   dijah  阅读(32)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示