BSOJ1527&BZOJ4129 Haruna's Breakfast

题目

BSOJ1527&BZOJ4129 Haruna’s Breakfast

树上询问路径 (mex) 且带单点修改。

分析

首先区间 (mex) 问题可以使用莫队+值域分块或者回滚莫队解决。

这里带修的话就需要带修莫队+值域分块或者带修回滚莫队。

再加上这是树上,所以可以树分块过后莫队即可。

关于序列上怎么做,我们这里只介绍前者,也就是莫队+值域分块,后者请自行看我的另外的文章。

首先莫队,然后值域分块直接维护 (cnt) ,大块维护当前区间的(cnt_ige 1)(i) 的个数

每次 (sqrt{n}) 询问即可。

代码

#include <bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
	x=0;char ch=getchar();bool f=false;
	while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	x=f?-x:x;
	return ;
}
template <typename T>
inline void write(T x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar(x%10^48);
	return ;
}
#define ll long long
const int N=1e5+5,INF=1e9+7;
struct Query{
    int u,v,t,id;
    Query(int u=0,int v=0,int t=0,int id=0):u(u),v(v),t(t),id(id){}
}Q[N];

struct Change{
    int u,las,nex;
    Change(int u=0,int las=0,int nex=0):u(u),las(las),nex(nex){}
}C[N];
int val[N],w[N],fa[N],dep[N],son[N],sta[N];
int siz[N],top[N],bl[N],a[N],sum[N];
bool vis[N];
int n,m,q,Top,idx,cnt1,cnt2,block;
ll res,Ans[N];
vector<int> vec[N];
void dfs1(int u,int f){
	int now=Top;
	sta[++Top]=u,fa[u]=f,dep[u]=dep[f]+1,siz[u]=1;//压入栈和更新信息 
	for(auto v:vec[u]){
		if(v==f) continue;
		dfs1(v,u);
		if(Top-now>block){//如果里面的点多于 B 个 
			idx++;//块编号 
			while(Top!=now) bl[sta[Top--]]=idx;//更新节点所属块 
		}
		siz[u]+=siz[v];
		if(siz[v]>siz[son[u]]) son[u]=v; 
	}
	return ;
}
void dfs2(int u,int f){//树剖预处理 
	top[u]=f;
	if(!son[u]) return ;
	dfs2(son[u],f);
	for(auto v:vec[u]){
		if(v==fa[u]||v==son[u]) continue;
		dfs2(v,v);
	}
	return ;
}
inline int QueryLca(int u,int v){//查询lca 
	while(top[u]!=top[v]){
		if(dep[top[u]]<dep[top[v]]) swap(u,v);
		u=fa[top[u]];
	}
	if(dep[u]<dep[v]) return u;
	return v;
}
inline bool cmp(Query a,Query b){//莫队排序 
	if(bl[a.u]==bl[b.u]){
		if(bl[a.v]==bl[b.v]) return a.t<b.t;
		return bl[a.v]<bl[b.v];
	}
	return bl[a.u]<bl[b.u];
}
int cnt[N],Cnt[N],Size,B;
inline void Update(int u){
	const int x=a[u];
	if(vis[u]) --cnt[x]?u:--Cnt[(x-1)/Size+1];
	else cnt[x]++?u:++Cnt[(x-1)/Size+1];
	vis[u]^=1;return ;
}
inline void Modify(int u,int t){//把u这个点的颜色换成t的影响 
	if(vis[u]) --cnt[a[u]]?u:--Cnt[(a[u]-1)/Size+1],cnt[t]++?u:++Cnt[(t-1)/Size+1];
	a[u]=t;
	return ;
}
inline void Move(int u,int v){//把u->v这条路径的更新了 
	if(dep[u]<dep[v]) swap(u,v);
	while(dep[u]>dep[v]) Update(u),u=fa[u];
	while(u!=v) Update(u),Update(v),u=fa[u],v=fa[v];
	return ;
}
int main(){
	read(n),read(q);
	block=pow(n,2.0/3);Size=sqrt(n);B=(n+2)/Size+1;
	for(int i=1;i<=n;i++) read(a[i]),a[i]=min(a[i],n+1),a[i]++,sta[i]=a[i];//a是最初的颜色 
	for(int i=1;i<n;i++){//建图 
		int u,v;read(u),read(v);
		vec[u].push_back(v),vec[v].push_back(u);
	}
	
	for(int i=1;i<=q;i++){
		int op,u,v;
		read(op),read(u),read(v);
		if(op==0) v=min(n+1,v),v++,C[++cnt1]=Change(u,sta[u],v),sta[u]=v;
		else ++cnt2,Q[cnt2]=Query(u,v,cnt1,cnt2);
	}
	memset(sta,0,sizeof(sta));
	dfs1(1,0),dfs2(1,1);
	while(Top>0) bl[sta[Top--]]=idx;
	
	sort(Q+1,Q+cnt2+1,cmp);
	int u,v,t;
	u=v=1,t=0;
	Update(1);
	for(int i=1;i<=cnt2;i++){
	
		while(t<Q[i].t) Modify(C[t+1].u,C[t+1].nex),t++;//修正时间 
		while(t>Q[i].t) Modify(C[t].u,C[t].las),--t;
		Update(QueryLca(u,v));//两个LCA在这里要单独讨论 
		if(u!=Q[i].u) Move(u,Q[i].u),u=Q[i].u;//u更新到u` 
		if(v!=Q[i].v) Move(v,Q[i].v),v=Q[i].v;//v更新到v` 
		Update(QueryLca(u,v));//讨论 
		res=1;
		while(Cnt[res]==Size) res++;
		res--;res=res*Size+1;
		while(cnt[res]) res++;
		Ans[Q[i].id]=res-1;
	}
	for(int i=1;i<=cnt2;i++) write(Ans[i]),putchar('
'); 
	return 0; 
}
原文地址:https://www.cnblogs.com/Akmaey/p/14764743.html