【题解】Luogu P7394 「TOCO Round 1」History

看到“回到 \(x\) 后的状态”,显然考虑可持久化线段树。记开灯的为 \(1\),关灯的为 \(0\),对于每个询问只需去查某些点的权值和即可。

考虑怎么将符合条件的点转化为区间。询问的是同一深度的点,可以考虑 bfs 序。考虑如果 \(y\) 是奇数,显然答案为 \(0\);否则询问的点就是 \(x\)\(\frac{y}{2}\) 级祖先在 \(x\) 这一层的后代,再去掉 \(x\)\(\frac{y}{2}-1\) 级祖先在 \(x\) 这一层的后代。考虑怎么去找到询问对应的区间。对于同一棵子树的同一深度,其 bfs 序是连续的。因此可以将询问先存下来,对于每个节点建线段树,存储某一深度的 bfs 序最大值和最小值。线段树合并即可。

时间复杂度分析,处理操作时每次都为 \(O(\log n)\),所有线段树合并的总时间复杂度为 \(O(n\log n)\),于是总的时间复杂度就为 \(O((n+m)\log n)\)

#include<bits/stdc++.h>
#define ll long long
#define il inline
#define pb push_back
#define pii pair<int,int>
#define mp make_pair
#define fir first
#define sec second
using namespace std;
namespace asbt{
namespace cplx{bool begin;}
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;
int n,m,dep[maxn];
int anc[maxn][22];
int bfn[maxn];
queue<int> q;
vector<int> e[maxn];
vector<pii> quj[maxn];
struct{
	int opt,x,y;
	int l1,r1,l2,r2;
}wt[maxn];
il void dfs1(int u,int fa){
	dep[u]=dep[fa]+1;
	anc[u][0]=fa;
	for(int i=1;i<=20;i++){
		anc[u][i]=anc[anc[u][i-1]][i-1];
	}
	for(int v:e[u]){
		if(v==fa){
			continue;
		}
		dfs1(v,u);
	}
}
il int ganc(int u,int k){
	int tmp=0;
	while(k){
		if(k&1){
			u=anc[u][tmp];
		}
		k>>=1,tmp++;
	}
	return u;
}
il void bfs(){
	int cnt=0;
	q.push(1);
	while(q.size()){
		int u=q.front();
		q.pop(),bfn[u]=++cnt;
		for(int v:e[u]){
			if(!bfn[v]){
				q.push(v);
			}
		}
	}
}
int rt[maxn],tot,ls[maxn*40],rs[maxn*40],sum[maxn*40],mn[maxn*40],mx[maxn*40];
il int New(){
	tot++;
	ls[tot]=rs[tot]=sum[tot];
	mn[tot]=inf,mx[tot]=-inf;
	return tot;
}
il void pushup(int id){
	sum[id]=sum[ls[id]]+sum[rs[id]];
}
il void build(int &id,int l,int r){
	id=New();
	if(l==r){
		return ;
	}
	int mid=(l+r)>>1;
	build(ls[id],l,mid);
	build(rs[id],mid+1,r);
}
il void add(int &id,int l,int r,int p,int v){
	if(!id){
		id=New();
	}
	if(l==r){
		mn[id]=min(mn[id],v);
		mx[id]=max(mx[id],v);
		return ;
	}
	int mid=(l+r)>>1;
	if(p<=mid){
		add(ls[id],l,mid,p,v);
	}
	else{
		add(rs[id],mid+1,r,p,v);
	}
	mn[id]=min(mn[ls[id]],mn[rs[id]]);
	mx[id]=max(mx[ls[id]],mx[rs[id]]);
}
il void upd(int &id,int fr,int l,int r,int p){
	id=New();
	if(l==r){
		sum[id]=sum[fr]^1;
		return ;
	}
	int mid=(l+r)>>1;
	if(p<=mid){
		rs[id]=rs[fr];
		upd(ls[id],ls[fr],l,mid,p);
	}
	else{
		ls[id]=ls[fr];
		upd(rs[id],rs[fr],mid+1,r,p);
	}
	pushup(id);
}
il int merge(int p,int q,int l,int r){
	if(!p||!q){
		return p+q;
	}
	if(l==r){
		int x=New();
		mn[x]=min(mn[p],mn[q]);
		mx[x]=max(mx[p],mx[q]);
		return x;
	}
	int mid=(l+r)>>1,x=New();
	ls[x]=merge(ls[p],ls[q],l,mid);
	rs[x]=merge(rs[p],rs[q],mid+1,r);
	mn[x]=min(mn[ls[x]],mn[rs[x]]);
	mx[x]=max(mx[ls[x]],mx[rs[x]]);
	return x;
}
il int query(int id,int L,int R,int l,int r){
	if(l>r||!id){
		return 0;
	}
	if(L>=l&&R<=r){
		return sum[id];
	}
	int mid=(L+R)>>1,res=0;
	if(l<=mid){
		res+=query(ls[id],L,mid,l,r);
	}
	if(r>mid){
		res+=query(rs[id],mid+1,R,l,r);
	}
	return res;
}
il int qmn(int id,int l,int r,int p){
	if(l==r){
		return mn[id];
	}
	int mid=(l+r)>>1;
	return p<=mid?qmn(ls[id],l,mid,p):qmn(rs[id],mid+1,r,p);
}
il int qmx(int id,int l,int r,int p){
	if(l==r){
		return mx[id];
	}
	int mid=(l+r)>>1;
	return p<=mid?qmx(ls[id],l,mid,p):qmx(rs[id],mid+1,r,p);
}
il void dfs2(int u,int fa){
	add(rt[u],1,n,dep[u],bfn[u]);
	for(int v:e[u]){
		if(v==fa){
			continue;
		}
		dfs2(v,u);
		rt[u]=merge(rt[u],rt[v],1,n);
	}
	for(pii v:quj[u]){
		int k=v.fir,id=v.sec;
		if(id>0){
			wt[id].l1=qmn(rt[u],1,n,k);
			wt[id].r1=qmx(rt[u],1,n,k);
		}
		else{
			id=-id;
			wt[id].l2=qmn(rt[u],1,n,k);
			wt[id].r2=qmx(rt[u],1,n,k);
		}
	}
}
namespace cplx{
	bool end;
	il double usdmem(){return (&begin-&end)/1048576.0;}
}
int main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n;
	for(int i=1,u,v;i<n;i++){
		cin>>u>>v;
		e[u].pb(v),e[v].pb(u);
	}
	dfs1(1,0),bfs();
	cin>>m;
	for(int i=1,opt,x,y;i<=m;i++){
		cin>>opt>>x;
		wt[i].opt=opt,wt[i].x=x;
		if(opt==2){
			cin>>y;
			wt[i].y=y;
			if((y&1)||!y){
				continue;
			}
			y>>=1;
			if(y>=dep[x]){
				continue;
			}
			x=ganc(wt[i].x,y);
			quj[x].pb(mp(dep[wt[i].x],i));
			x=ganc(wt[i].x,y-1);
			quj[x].pb(mp(dep[wt[i].x],-i));
		}
	}
	mn[0]=inf,mx[0]=-inf;
	dfs2(1,0);
	tot=0;
	build(rt[0],1,n);
	for(int i=1,opt,x,y;i<=m;i++){
		opt=wt[i].opt,x=wt[i].x,y=wt[i].y;
		switch(opt){
			case 1:{
				upd(rt[i],rt[i-1],1,n,bfn[x]);
				break;
			}
			case 2:{
				rt[i]=rt[i-1];
				if(y&1){
					cout<<"0\n";
				}
				else if(!y){
					cout<<query(rt[i],1,n,bfn[x],bfn[x])<<"\n";
				}
				else{
					y>>=1;
					if(y>=dep[x]){
						cout<<"0\n";
					}
					else{
						cout<<query(rt[i],1,n,wt[i].l1,wt[i].l2-1)+query(rt[i],1,n,wt[i].r2+1,wt[i].r1)<<"\n";
					}
				}
				break;
			}
			default:{
				rt[i]=rt[x];
				break;
			}
		}
	}
	return 0;
}
}
int main(){return asbt::main();}
posted @ 2025-02-17 21:40  zhangxy__hp  阅读(14)  评论(0)    收藏  举报