P11364 [NOIP2024] 树上查询

P11364 [NOIP2024] 树上查询

题目描述

有一天小 S 和她的朋友小 N 一起研究一棵包含了 \(n\) 个结点的树。

这是一棵有根树,根结点编号为 \(1\),每个结点 \(u\) 的深度 \(\text{dep}_ u\) 定义为 \(u\) 到 \(1\) 的简单路径上的结点数量。

除此之外,再定义 \(\text{LCA*}(l, r)\) 为编号在 \([l, r]\) 中所有结点的最近公共祖先,即 \(l, l + 1, \dots , r\) 的公共祖先结点中深度最大的结点。

小 N 对这棵树提出了 \(q\) 个询问。在每个询问中,小 N 都会给出三个参数 \(l, r, k\),表示他想知道 \([l, r]\) 中任意长度大于等于 \(k\) 的连续子区间的最近公共祖先深度的最大值,即

\[\max_{l\le l'\le r'\le r \land r'-l'+1\ge k}\text{dep}_ {\text{LCA*}(l', r')} \]

你的任务是帮助小 S 来回答这些询问。

输入格式

输入的第一行包含一个正整数 \(n\),表示树的结点数。

接下来 \(n - 1\) 行,每行包含两个正整数 \(u, v\),表示存在一条从结点 \(u\) 到结点 \(v\) 的边。

第 \(n + 1\) 行包含一个正整数 \(q\),表示询问的数量。

接下来 \(q\) 行,每行包含三个正整数 \(l, r, k\),描述了一次询问。

输出格式

对于每次询问输出一行,包含一个整数,表示对应的答案。

输入输出样例 #1

输入 #1

6
5 6
6 1
6 2
2 3
2 4
3
2 5 2
1 4 1
1 6 3

输出 #1

3
4
3

说明/提示

【样例 1 解释】

图 3

  • 对于第一组询问,\(\text{LCA*}(2, 3) = 2, \text{LCA*}(3, 4) = 2, \text{LCA*}(4, 5) = 6\),\(2\) 的深度为 \(3\),\(6\) 的深度为 \(2\),因此答案为 \(\max\{3, 3, 2\} = 3\)。

  • 对于第二组询问,答案为 \(1, 2, 3, 4\) 四个结点的最大深度,因此答案为 \(4\)。

  • 对于第三组询问,\(\text{LCA*}(1, 3) = 1, \text{LCA*}(2, 4) = 2, \text{LCA*}(3, 5) = 6, \text{LCA*}(4, 6) = 6\),依旧是 \(2\) 的深度最大,因此答案为 \(3\)。

【样例 2】

见附件的 query/query2.in 与 query/query2.ans。

该样例满足 \(n, q ≤ 500\)。

【样例 3】

见附件的 query/query3.in 与 query/query3.ans。

该样例满足 \(n, q ≤ 10^5\) 且树符合链的形态。

【样例 4】

见附件的 query/query4.in 与 query/query4.ans。

该样例满足 \(n, q ≤ 5 × 10^5\)。

【数据范围】

对于所有的测试数据,保证:\(1 ≤ n, q ≤ 5 × 10^5 , 1 ≤ l ≤ r ≤ n, 1 ≤ k ≤ r - l + 1\)。

::cute-table{tuack}

测试点编号 \(n,q\le\) 特殊限制
\(1\sim2\) \(500\) 无
\(3\sim5\) \(5000\) ^
\(6\sim9\) \(10^5\) 满足性质 A
\(10\sim13\) \(5\times10^5\) ^
\(14\sim16\) ^ 满足性质 B
\(17\sim20\) \(10^5\) 无
\(21\sim25\) \(5\times10^5\) ^

性质 A:保证输入的树符合链的形态,且根结点的度数为 \(1\)。

性质 B:对于每个询问保证 \(k = r - l + 1\)。

#include<bits/stdc++.h>
#define wk(x) write(x),putchar(' ')
#define wh(x) write(x),putchar('\n')
#define L (p<<1)
#define R ((p<<1)|1)
#define MID ((l+r)>>1)
#define N 600005

using namespace std;
int n,m,k,jk,ans,sum,num,cnt,tot;
int head[N],dis[N],vis[N],f[N][23];
int mx[N][22],dep[N];
vector<int> q[N],p[N];

void read(int &x)
{
	x=0;int ff=1;char ty;
	ty=getchar();
	while(!(ty>='0'&&ty<='9'))
	{
		if(ty=='-') ff=-1;
		ty=getchar();
	}
	while(ty>='0'&&ty<='9')
		x=(x<<3)+(x<<1)+ty-'0',ty=getchar();
	x*=ff;return;
}

void write(int x)
{
	if(x==0){putchar('0');return;}
	if(x<0){x=-x;putchar('-');}
	char asd[201];int ip=0;
	while(x) asd[++ip]=x%10+'0',x/=10;
	for(int i=ip;i>=1;i--) putchar(asd[i]);
	return;
}

struct Quest{
	int l,r,id,z,k;
}a[N];

struct Quest1{
	int l,r,z;
}b[N];

struct M{
	struct T{int l,r,max;}T[N<<2];
	
	void push(int p){
		T[p].max=max(T[L].max,T[R].max);
		return;
	}
	
	void build(int p,int l,int r){
		T[p].l=l;T[p].r=r;
		if(l==r){T[p].max=0;return;}
		build(L,l,MID);build(R,MID+1,r);
		T[p].max=0;return;
	}
	
	void build1(int p,int l,int r){
		T[p].l=l;T[p].r=r;
		if(l==r){T[p].max=dep[l];return;}
		build1(L,l,MID);build1(R,MID+1,r);
		push(p);return;
	}
	
	void cge(int p,int l,int r,int x,int z){
		if(l==r){T[p].max=max(T[p].max,z);return;}
		if(MID>=x) cge(L,l,MID,x,z);
		else cge(R,MID+1,r,x,z);
		push(p);return;
	}
	
	int qry(int p,int l,int r,int x,int y,int z=0){
		if(x<=l&&r<=y) return T[p].max;
		if(MID>=x) z=qry(L,l,MID,x,y);
		if(MID<y) z=max(z,qry(R,MID+1,r,x,y));
		push(p);return z;
	}
}T;

struct P{
	int nxt,to;
}v[N<<1];

void add(int x,int y){
	v[++cnt]=(P){head[x],y};
	head[x]=cnt;return;
}

void dg(int x,int y){
	dep[x]=dep[y]+1;
	for(int i=head[x];i;i=v[i].nxt){
		if(v[i].to==y) continue;
		mx[v[i].to][0]=x;dg(v[i].to,x);
	}return; 
}

int LCA(int x,int y){
	if(dep[x]<dep[y]) swap(x,y);
	for(int i=__lg(dep[x]);i>=0;i--) if(dep[mx[x][i]]>=dep[y]) x=mx[x][i];
	if(x==y) return x;
	for(int i=__lg(dep[x]);i>=0;i--) if(mx[x][i]!=mx[y][i]) x=mx[x][i],y=mx[y][i];
	return mx[x][0];
}

int G(int x,int y){int l=__lg(y-x+1);
	return min(f[x][l],f[y-(1<<l)+1][l]);
}

signed main()
{
//	freopen("lazy.in","r",stdin);
//	freopen("lazy.out","w",stdout);
	read(n);
	for(int i=1,x,y;i<n;i++){
		read(x),read(y);
		add(x,y),add(y,x);
	}dg(1,0);
	for(int i=1;i<=21;i++)
		for(int j=1;j<=n;j++) mx[j][i]=mx[mx[j][i-1]][i-1];
	read(jk);
	for(int i=1;i<=jk;i++) read(a[i].l),read(a[i].r),read(a[i].k);
	for (int i=1;i<n;i++) f[i][0]=dis[i]=dep[LCA(i,i+1)];f[n][0]=2e5;
	for (int j=1;j<=__lg(n);j++)
		for (int i=1;i<=n-(1<<j)+1;i++)
			f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
	for(int i=1;i<n;i++){
		int l=1,r=i,mid;
		while(l<=r){
			if(G(MID,i)<dis[i]) l=MID+1;
			else r=MID-1,b[i].l=r+1;
		}l=i,r=n;
		while(l<=r){
			if(G(i,MID)<dis[i]) r=MID-1;
			else l=MID+1,b[i].r=l-1;
		}b[i].z=dis[i];b[i].r=min(n,b[i].r+1); 
		// wk(b[i].l),wk(b[i].r),wh(b[i].z);
	}
//	return 0;
	//l<=L<=R<=r
	T.build(1,1,n);
	for(int i=1;i<=n;i++) q[b[i].l].push_back(i);
	for(int i=1;i<=jk;i++) p[a[i].l].push_back(i);
	for(int i=1;i<=n;i++){
		for(int j=0;j<(int)q[i].size();j++) T.cge(1,1,n,b[q[i][j]].r,b[q[i][j]].z);
		for(int j=0;j<(int)p[i].size();j++) a[p[i][j]].z=max(a[p[i][j]].z,T.qry(1,1,n,a[p[i][j]].r,n));
	}
	//L<=l<=R<=r
	T.build(1,1,n);
	for(int i=1;i<=n;i++) q[b[i].l].clear();
	for(int i=1;i<=jk;i++) p[a[i].l].clear();
	for(int i=1;i<=n;i++) q[b[i].r-b[i].l+1].push_back(i);
	for(int i=1;i<=jk;i++) p[a[i].k].push_back(i);
	for(int i=n;i>=1;i--){
		for(int j=0;j<(int)q[i].size();j++) T.cge(1,1,n,b[q[i][j]].l,b[q[i][j]].z);
		for(int j=0;j<(int)p[i].size();j++) a[p[i][j]].z=max(a[p[i][j]].z,T.qry(1,1,n,a[p[i][j]].l,a[p[i][j]].r-a[p[i][j]].k+1));
	}
	//l<=L<=r<=R
	T.build(1,1,n);
	for(int i=n;i>=1;i--){
		for(int j=0;j<(int)q[i].size();j++) T.cge(1,1,n,b[q[i][j]].r,b[q[i][j]].z);
		for(int j=0;j<(int)p[i].size();j++) a[p[i][j]].z=max(a[p[i][j]].z,T.qry(1,1,n,a[p[i][j]].l+a[p[i][j]].k-1,a[p[i][j]].r));
	}
	T.build1(1,1,n);
	for(int i=1;i<=jk;i++){
		if(a[i].k==1){
			wh(T.qry(1,1,n,a[i].l,a[i].r));
			continue;
		}
		wh(a[i].z);
//		if(i==19) return 0; 
	}
	return 0;
}
posted @ 2025-12-26 14:06  Red_river_hzh  阅读(34)  评论(0)    收藏  举报