Featured image of post 洛谷P6071『MdOI R1』Treequery

洛谷P6071『MdOI R1』Treequery

主席树+倍增+dfn维护的树上计数题

原题链接

考虑用主席树+倍增+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)$

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#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;
}
2024 crpboy, All rights reserved.