bzoj4569 [Scoi2016]萌萌哒 并查集+st表

ST表与并查集结合
本文介绍了一种将ST表与并查集相结合的方法,用于优化区间查询问题。通过对比线段树与ST表的特点,说明了如何利用ST表减少冗余计算,并通过并查集进一步优化区间操作。

这个题非常巧妙,它描述了一种新的延迟标记关系。。

正常的线段树是用n*4的空间描述一个序列,所以对于一段区间,有可能会有log个点对应一个点

而线段树是利用尽量小的空间使查询变为log

st表是nlogn的空间,对于一段区间,是可以做到一一对应的,它只是预处理比线段树暴力了一些

所以这个题要放到线段树上的话就需要对两个区间进行拆分,在线段树的节点上更新father数组

这样散开的点有可能是log^2的,而且给点打标记比较麻烦

而st表的话,由于区间长度是一一对应的,所以只需要打两个标记,重叠的标记用并查集并起来

然后就相当于线段树的枚举单点查询操作了,一层层的pushdown(不是一层层的也可以,不过麻烦)

这个题对于暴力并查集的优化就是对区间也用并查集,用延迟标记的叠加来减少重复操作


码:

#include<iostream>
#include<cstdio>
#define P 1000000007
using namespace std;
int f[100005][25],o,n,m,i,j,er[25],l1,l2,r1,r2,cnt,ans;
int zhao(int o,int x)
{
	if(f[o][x]!=o)f[o][x]=zhao(f[o][x],x);
	return f[o][x];
}
int main()
{
scanf("%d%d",&n,&m);
er[0]=1;
for(i=1;i<=20;i++)er[i]=er[i-1]*2;
for(i=1;i<=n;i++)
for(j=0;j<=20;j++)
f[i][j]=i;
for(j=1;j<=m;j++)	
	{
		scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
		int o=r1-l1+1;
		for(i=0;i<=20;i++)
		if(er[i]&o) 
		{
	int f1=zhao(f[l1][i],i),f2=zhao(f[l2][i],i);		
    if(f1!=f2)f[f1][i]=f2;
l1+=er[i];
l2+=er[i];   			
		}
	}
	for(j=20;j>=1;j--)
	{
		for(i=1;i<=n;i++)
{
	//分下去	
	if(i+er[j]-1>n)continue;
o=zhao(i,j);
	int ll=zhao(o,j-1);
	int lll=zhao(i,j-1);
	f[ll][j-1]=lll;	
	int rr=zhao(o+er[j-1],j-1);
	int rrr=zhao(i+er[j-1],j-1);
	f[rr][j-1]=rrr;
}				
	}
	for(i=1;i<=n;i++)
	if(zhao(i,0)==i)++cnt;
	ans=9;
	for(i=1;i<cnt;i++)
	ans=1ll*ans*10%P;
	printf("%d",ans);
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值