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\) 的连续子区间的最近公共祖先深度的最大值,即
你的任务是帮助小 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 解释】

-
对于第一组询问,\(\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;
}
本文来自博客园,作者:Red_river_hzh,转载请注明原文链接:https://www.cnblogs.com/Red-river-hzh/p/19404491

浙公网安备 33010602011771号