CF1801E 题解

CF1801E

思路

并查集将权值相同的连在一起,取可行区间的并集。可以 \(O(n^2)\)。考虑优化,总共只有 \(n-1\) 次有效合并,只要没有重复检查已经连通的点就可以保证复杂度。

倍增 \(u\) 向上 \(2^i\) 个祖先的状态,代表从下往上和从上往下的区间。将两条路径倍增合并,\(O(\log n)\) 次合并等长区间。每次合并时向下一层递归合并,如果已经是一个连通块的及时退出。一直到单点合并时,去掉旧贡献加上新贡献。复杂度 \(O(n\log n)\)

卡常方面,将倍增的 \(\log n\) 一维放在 \(n\) 一维前面,路径压缩加按秩合并,不开 long long。实在过不了再交几次。

code

int n,q,ans=1;
int head[maxn],tot;
struct nd{
	int nxt,to;
}e[maxn<<1];
void add(int u,int v){e[++tot]={head[u],v};head[u]=tot;}
int l[maxn],r[maxn];
inline int ksm(int a,int b=mod-2){
	int ans=1;
	while(b){
		if(b&1)ans=1ll*ans*a%mod;
		a=1ll*a*a%mod;
		b>>=1;
	}
	return ans;
}
int fa[18][maxn],dep[maxn];
int f[18][maxn<<1],siz[18][maxn<<1];
int fd(int x,int k){
	if(x==f[k][x])return x;
	return f[k][x]=fd(f[k][x],k);
}
void merge(int x,int y,int id){
	// if(!id)cout<<x<<" "<<y<<"\n";
	x=fd(x,id),y=fd(y,id);
	if(x==y)return ;
	if(siz[id][x]<siz[id][y])swap(x,y);
	if(!id){
		ans=1ll*ans*ksm(max(0,r[x]-l[x]+1))%mod;
		ans=1ll*ans*ksm(max(0,r[y]-l[y]+1))%mod;
		l[x]=max(l[x],l[y]),r[x]=min(r[x],r[y]);
		ans=1ll*ans*max(0,r[x]-l[x]+1)%mod;
		// cout<<x<<" "<<y<<" "<<ans<<"\n";
	}
	f[id][y]=x,siz[id][x]+=siz[id][y];
}
void dfs(int u){
	dep[u]=dep[fa[0][u]]+1;
	for(int i=1;i<=17;i++)fa[i][u]=fa[i-1][fa[i-1][u]];
	for(int i=0;i<=17;i++)f[i][u]=u,siz[i][u]=1,f[i][u+n]=u+n,siz[i][u+n]=1;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		fa[0][v]=u;dfs(v);
	}
}
int lca(int u,int v){
	if(dep[u]<dep[v])swap(u,v);
	for(int i=17;~i;i--)if(dep[fa[i][u]]>=dep[v])u=fa[i][u];
	if(u==v)return u;
	for(int i=17;~i;i--)if(fa[i][u]!=fa[i][v])u=fa[i][u],v=fa[i][v];
	return fa[0][u];
}
int kth(int u,int k){
	for(int i=17;~i;i--)if(k&(1<<i))u=fa[i][u];
	return u;
}
void mer1(int u,int v,int id){
	if(fd(u,id)==fd(v,id))return ;
	if(!id){
		merge(u,v,id);
		return ;
	}
	merge(u,v,id);
	mer1(u,v,id-1),mer1(fa[id-1][u],fa[id-1][v],id-1);
}
void mer2(int u,int v,int id){
	if(fd(u,id)==fd(v+n,id))return ;
	if(!id){
		merge(u,v,id);
		return ;
	}
	merge(u+n,v,id),merge(u,v+n,id);
	mer2(u,fa[id-1][v],id-1),mer2(fa[id-1][u],v,id-1);
}
void work(){
	n=read();
	for(int i=2;i<=n;i++){
		int u=read();
		add(u,i);
	}
	dfs(1);
	for(int i=1;i<=n;i++){
		l[i]=read(),r[i]=read();
		ans=1ll*ans*max(0,r[i]-l[i]+1)%mod;
	}
	q=read();
	while(q--){
		int a=read(),b=read(),c=read(),d=read(),tp1=lca(a,b),tp2=lca(c,d);
		int dis=min(dep[a]-dep[tp1],dep[c]-dep[tp2]);
		for(int i=17;~i;i--)if(dis&(1<<i))mer1(a,c,i),a=fa[i][a],c=fa[i][c];
		dis=min(dep[b]-dep[tp1],dep[d]-dep[tp2]);
		for(int i=17;~i;i--)if(dis&(1<<i))mer1(b,d,i),b=fa[i][b],d=fa[i][d];
		// cout<<tp1<<" "<<tp2<<" "<<ans<<"\n";
		if(a==tp1){
			dis=dep[b]-dep[tp1]+1;
			for(int i=17;~i;i--)if(dis&(1<<i))dis^=(1<<i),mer2(b,kth(c,dis),i),b=fa[i][b];
		}
		else{
			dis=dep[a]-dep[tp1]+1;
			for(int i=17;~i;i--)if(dis&(1<<i))dis^=(1<<i),mer2(a,kth(d,dis),i),a=fa[i][a];
		}
		printf("%d\n",ans);
	}
}
posted @ 2024-05-10 19:59  yhddd  阅读(10)  评论(0编辑  收藏  举报