牛半仙的妹子Tree题解

题面

做法

先补一下ST表求LCA的做法。

欧拉序就是dfs遍历这颗树经过每个节点的顺序。

欧拉序有一个优美的性质,就是给定两个端点 \(l,r\) ,则 \([l,r]\) 之间深度最小值即是 \(l,r\) 的LCA。

我们 \(dfs\) 时需要统计 \(dep_u,dfn_u\) 以及欧拉序

lca

如图,其欧拉序为1 5 6 5 1 2 4 2 3 2 1

比如6与4之间的最小值为1,显然该点就是这两点的LCA。

由于一个有儿子的点可能被经过不止一次,所以序列长度比 \(n\) 大很正常。

我们还需要一个dfn数组来统计每个节点第一次被经过的时间,当然这个时间戳依然可能比 \(n\) 大,所代表的就是其第一次在欧拉序中出现的位置。

对于上图,其dfn1 6 9 7 2 3,两者的联系就在于\(dfn_i\) 代表的是对于节点 \(i\) 第一次出现在欧拉数组中的下标是 \(dfn_i\)

比如 \(dfn_2\) 为6,而其在欧拉序中首次出现的位置也是6。

st_2

欧拉序找LCA就是对于一个欧拉序数组,一组查询为 \(u,v\),我们应当在 \([dfn_u,dfn_v]\) 间找深度最小值,ST表显然可以维护。

在建表时,由于欧拉序的性质,应当选择深度较小的,而不是简单的取min(st[i][j-1],st[i+(1<<(j-1))][j-1])

在询问时,对于两个点 \(u,v\) ,先利用 \(dfn_u,dfn_v\) 找到在欧拉序中第一次出现的位置,然后再取深度较小点作为LCA。

再回到题目,不妨朴素的想,考虑每个点是否被染色,就要遍历上一次清零后的所有染色操作,设染色操作染了 \(x\),询问点是 \(y\)\(dis_{x,y}\) 表示两点距离, \(TIME_i\) 表示对于 \(i\) 点操作的时间,如果 \(dis_{x,y} \le TIME_{y}-TIME_{x}\) 那显然已经扩展到了。

考虑分块,由于操作是按时间顺序排序的,我们对于操作分块。

我们设块长为 \(len\) ,对于每个块内的染色操作,我们直接暴力判断,即在一个块内从上一次清零时刻+1开始(可能本块没有,直接从左端点开始)。

还有一种情况,就是上一次清零在块外面(上面的情况已经保证统计到被块内染色的情况),如果我们能够知道该点是否被块外的染色操作染色,即可 \(O(1)\) 判断。

假设该块之前的都已经算完了,我们现在枚举染色时间,判断该块中的染色操作是否会更新要染的这个点的染色时间,因为如果当前染色操作的时间比该点被染色的时间还要晚,那显然不用更新,如果可以,将当前块的所有染色操作加入队列并更新被染点的时间。进行Bfs,如果染色操作会使某个点最早被染色时间更早就修改,否则不修改,枚举完时间后将队列中剩下的点继续扩展直到遍历整棵树。

这样复杂度是 \(O(n)\) 的。

块长为 \(len\) 块数为 \(m/len\) ,时间复杂度为 \(O(m/len \times (n + len^2))\)\(len\)\(\sqrt{n}\)\(n,m\) 同阶即为 \(O(m \times \sqrt{n})\)

code
#include<bits/stdc++.h>
using namespace std;
#define syt cerr<<"sytakioi"<<endl;
const int maxn=2e5+10,inf=0x3f3f3f3f;
struct node {
	int nxt,to;
} edge[maxn<<1];
struct OP {
	int op,x;
} op[maxn<<1];
int head[maxn<<1],cnt=0;
void add(int u,int v) {
	cnt++;
	edge[cnt].to=v;
	edge[cnt].nxt=head[u];
	head[u]=cnt;
}
int st[maxn<<1][30],fa[maxn<<1];
int tim[maxn],l[maxn],r[maxn];
int n,m,num=0;
int	dep[maxn<<1],rl[maxn<<1],dfn[maxn<<1];
void dfs(int u,int fath) {
	rl[++num]=u;
	dep[u]=dep[fath]+1;
	dfn[u]=num;
	fa[u]=fath;
	for(int i=head[u]; i; i=edge[i].nxt) {
		int v=edge[i].to;
		if(v==fath) continue ;
		dfs(v,u);
		rl[++num]=u;
	}
}
int lca(int x,int y) {
	int u=dfn[x],v=dfn[y];
	if(u>v)
		swap(u,v);
	int len=log2(v-u+1);
	int uu=st[u][len],vv=st[v-(1<<len)+1][len];
	if(dep[uu]<dep[vv])
		return uu;
	else
		return vv;
}
int dis(int u,int v) {
	return dep[u]+dep[v]-2*dep[lca(u,v)];
}
int s;
int main() {
	cin>>n>>m;
	for(int i=1; i<n; i++) {
		int u,v;
		cin>>u>>v;
		add(u,v),add(v,u);
	}
	dfs(1,0);
//	for(int i=1; i<=n; i++)
//		cout<<dfn[i]<<" ";
//	cout<<endl;
//	for(int i=1; i<=num; i++)
//		cout<<rl[i]<<" ";
	memset(tim,inf,sizeof(tim));
	for(int i=1; i<=num; i++)
		st[i][0]=rl[i];
	for(int j=1; j<=log2(num); j++) {
		for(int i=1; i+(1<<j)-1<=num; i++) {
			int u=st[i][j-1],v=st[i+(1<<(j-1))][j-1];
			if(dep[u]<dep[v])
				st[i][j]=u;
			else
				st[i][j]=v;
		}
	}
	for(int i=1; i<=m; i++) {
		cin>>op[i].op>>op[i].x;
	}
	int len=sqrt(n);
	int blocks=m/len;
	if(blocks*len<m)blocks++;
	for(int i=1; i<=blocks; i++) {
		l[i]=len*(i-1)+1,r[i]=len*i;
	}
	r[blocks]=m;
	int gc=0;
	queue<int> q;
	//for(int i=1; i<=blocks; i++)
	//	cout<<" bl: "<<l[i]<<" "<<r[i]<<endl;
	for(int i=1; i<=blocks; i++) {
		//syt
//		for (int j = 1; j <= n; j++) {
//			cout<<tim[j]<<" ";
//		}
//		cout<<endl;
		for(int j=l[i]; j<=r[i]; j++) {
			//syt
			if(op[j].op==1) continue;
			else if(op[j].op==2) gc=j;
			else {
				bool flag=0;
				for(int k=max(gc+1,l[i]); k<=j-1; k++)

					if(op[k].op==1 && j-k>=dis(op[k].x,op[j].x)) {
						flag=1;
						break;
					}
				//cout<<flag;
				if(gc<l[i] && tim[op[j].x]<=j) flag=1;
				//syt
				if(flag==1) {
					cout<<"wrxcsd"<<endl;

				} else
					cout<<"orzFsYo"<<endl;

			}
		}
		while(!q.empty())
			q.pop();
		if(gc>=l[i])
			for(int j=1; j<=n; j++)
				tim[j]=inf;
		for(int j=max(gc+1,l[i]); j<=r[i]; j++) {
			if(op[j].op==1 && j<tim[op[j].x])
				tim[op[j].x]=j,q.push(op[j].x);
			while(!q.empty()) {
				int u=q.front();
				if(tim[u]>j)break;
				q.pop();
				for(int I=head[u]; I; I=edge[I].nxt) {
					int v=edge[I].to;
					if(tim[v]>tim[u]+1) {
						tim[v]=tim[u]+1;
						q.push(v);
					}
				}
				if(tim[fa[u]]>tim[u]+1 && fa[u]) {
					tim[fa[u]]=tim[u]+1;
					q.push(fa[u]);
				}
			}
		}
		while(!q.empty()) {
			int u=q.front();
			q.pop();
			for(int I=head[u]; I; I=edge[I].nxt) {
				int v=edge[I].to;
				if(tim[v]>tim[u]+1) {
					tim[v]=tim[u]+1;
					q.push(v);
				}
			}
			if(tim[fa[u]]>tim[u]+1 && fa[u]) {
				tim[fa[u]]=tim[u]+1;
				q.push(fa[u]);
			}
		}
	}
	return 0;
}
//
/*
6 5
1 2
2 3
2 5
1 4
4 6
*/
posted @ 2024-11-19 08:16  p7gab  阅读(14)  评论(0编辑  收藏  举报  来源