LoadPageFault
LoadPageFault
发布于 2026-02-25 / 24 阅读
0
0

题解 洛谷P6071『MdOI R1』Treequery

考虑用主席树 + 倍增 +dfn 维护

首先,当p\in[l,r],或者 p 的祖先和子树内均有点x\in[l,r]的时候,答案必为 0。

除去以上情况,这些点要么都在我的祖先的子树(且 p 不在这些子树中)内,要么都在p 的子树内

祖先情况

  • 需要找到我的一个祖先点 x 满足:

    1. [l,r]的点都不在点 x 的子树内

    2. x 是满足第一种情况的最高点

    考虑用倍增维护,主席树查询[l,r]上的和即可

    其中,主席树对编号开点,以 dfn 作为插入的先后顺序

  • 或者需要找到一个不处于 p 子树内的点 x 满足:

    1. x 为所有y\in[l,r]的 lca

    2. 点 p 不在 x 的子树内

    直接倍增判断是否符合答案即可,最终答案就是 x 到 p 的路径长度

子树情况

需要找到 p 的子树内的一个节点 x 满足:

  1. [l,r]的点都在点 x 的子树内

  2. x 是满足第一种情况的最低点

怎样找到 x?随便挑一个点y\in[l,r],我要的答案点 x 一定在它到p的路径上

那么直接倍增跳就好了

时间复杂度 O(n \log^2 n)

实现

#include<bits/stdc++.h>
using namespace std;

#define dd ch=getchar()
int read()
{
	char dd;int x=0;bool f=false;
	while(!isdigit(ch))f|=ch=='-',dd;
	while(isdigit(ch))x=x*10+ch-48,dd;
	return f?-x:x;
}
#undef dd
void write(int x)
{
	if(x<0)x=-x,putchar('-');
	if(x>9)write(x/10);
	putchar(x%10+48);
}
#define writesp(x) (write(x),putchar(' '))
#define writeln(x) (write(x),putchar('\n'))

const int N=2e5+5;

int n,q;
struct node
{
	int v,w,nxt;
}a[N<<1];
int head[N],cnt=0;
void add(int u,int v,int w)
{
	a[++cnt].v=v;
	a[cnt].w=w;
	a[cnt].nxt=head[u];
	head[u]=cnt;
}

int tot=0;
int rt[N],t[N*50],ls[N*50],rs[N*50],fa[N][25];
void push_up(int p)
{
	t[p]=0;
	if(ls[p])t[p]+=t[ls[p]];
	if(rs[p])t[p]+=t[rs[p]];
}
int modify(int pre,int l,int r,int pos)
{
	int p=++tot;
	ls[p]=ls[pre],rs[p]=rs[pre];
	if(l==r){t[p]=1;return p;}
	int mid=(l+r)>>1;
	if(pos<=mid)ls[p]=modify(ls[pre],l,mid,pos);
	else rs[p]=modify(rs[pre],mid+1,r,pos);
	push_up(p);
	return p;
}
int query(int p,int l,int r,int L,int R)
{
	if(!p)return 0;
	if(L<=l&&r<=R)return t[p];
	int mid=(l+r)>>1,ans=0;
	if(L<=mid)ans+=query(ls[p],l,mid,L,R);
	if(mid<R)ans+=query(rs[p],mid+1,r,L,R);
	return ans;
}

int size[N],dep[N],deep[N],dfn[N],num=0;
void dfs(int u)
{
	size[u]=1;
	dfn[u]=++num;
	rt[num]=modify(rt[num-1],1,n,u);
	for(int i=1;i<=20;i++)
		fa[u][i]=fa[fa[u][i-1]][i-1];
	for(int i=head[u];i;i=a[i].nxt)
	{
		int v=a[i].v,w=a[i].w;
		if(v==fa[u][0])continue;
		dep[v]=dep[u]+w;deep[v]=deep[u]+1;
		fa[v][0]=u;
		dfs(v);
		size[u]+=size[v];
	}
}
int getres(int x,int l,int r)
{
	return query(rt[dfn[x]+size[x]-1],1,n,l,r)-query(rt[dfn[x]-1],1,n,l,r);
}
int lca(int x,int y)
{
	if(deep[x]<deep[y])swap(x,y);
	for(int i=20;i>=0;i--)
		if(deep[fa[x][i]]>=deep[y])
			x=fa[x][i];
	if(x==y)return x;
	for(int i=20;i>=0;i--)
		if(fa[x][i]!=fa[y][i])
			x=fa[x][i],y=fa[y][i];
	return fa[x][0];
}
int query1(int x,int l,int r)
{
	int o=x;
	if(getres(o,l,r))return 0;
	for(int i=20;i>=0;i--)
		if(fa[x][i]&&!getres(fa[x][i],l,r))
			x=fa[x][i];
	x=fa[x][0];
	if(!x)return 0;
	return dep[o]-dep[x];
}
int query2(int x,int l,int r)
{
	int o=x;x=l;
	if(getres(o,l,r)!=r-l+1)return 0;
	for(int i=20;i>=0;i--)
		if(fa[x][i]&&getres(fa[x][i],l,r)!=r-l+1)
			x=fa[x][i];
	if(getres(x,l,r)!=r-l+1)x=fa[x][0];
	if(!x)return 0;
	return dep[x]-dep[o];
}
int query3(int x,int l,int r)
{
	int o=x;x=l;
	if(getres(o,l,r))return 0;
	for(int i=20;i>=0;i--)
		if(fa[x][i]&&getres(fa[x][i],l,r)!=r-l+1)
			x=fa[x][i];
	if(getres(x,l,r)!=r-l+1)x=fa[x][0];
	if(!x||getres(x,o,o)==1)return 0;
	return dep[o]+dep[x]-dep[lca(x,o)]*2;
}

int main()
{
//	freopen("6071.in","r",stdin);
//	freopen("6071.out","w",stdout);
	n=read(),q=read();
	for(int i=1,u,v,w;i<n;i++)
		u=read(),v=read(),w=read(),add(u,v,w),add(v,u,w);
	dfs(1);
	
	int lasans=0;
	while(q--)
	{
		int p=read()^lasans,l=read()^lasans,r=read()^lasans;
		writeln(lasans=max(query1(p,l,r),max(query2(p,l,r),query3(p,l,r))));
	}
	return 0;
}

评论