集合求交,51nod1818,根号分治

正题

      Portal

      这题发现总的元素数量不超过M,所以我们可以对一个集合内的元素数量来根号分治。

      当询问的|S_p|<T时,暴力维护每一个权值以位置为关键字的线段树(动态开点),这部分的时间复杂度是O(m \log_2 n+mT\log_2 n )

      当询问的|S_p|>=T时,我们对于这些特殊的集合维护一个以位置为关键字的树状数组,每个位置的权值就是该集合与特殊集合的交集,更新显然,每次查询直接差分前缀和即可。这部分的时间复杂度为O(\frac{m}{T}m\log_2n+m\log_2n)

      这两个都是最坏时间复杂度,当T=\sqrt m时,有最小时间复杂度。

      但是为了避免麻烦,我们可以直接设为T=\left \lceil \frac{m}{1000} \right \rceil。就保证了特殊集合最多只有1000个。

      发现空间上还是爆炸,直接考虑把空间开小一点,或者选择vector,因为实际上的特殊集合并没有那么多。

      反正我空间是卡过去的,时间上没有问题。

#include
#include
#include
#include
#include
#include
#define lowbit(x) (x&(-x))
using namespace std;

const int N=40010,M=200010,A=1000000;
int n,m,bound,tot,num;
vector S[N],V[A+1];
bool tf[501][A+1];
int root[A+1],id[N];
int t[M*16],ls[M*16],rs[M*16];
int sum[501][N];

void insert(int&now,int d,int l,int r){
	if(now==0) now=++num;
	t[now]++;
	if(l==r) return ;
	int mid=(l+r)/2;
	if(d<=mid) insert(ls[now],d,l,mid);
	else insert(rs[now],d,mid+1,r);
}

void add(int*now,int x,int t){
	while(x<=n){
		now[x]+=t;
		x+=lowbit(x);
	}
	return ;
}

int get_tot(int now,int x,int y,int l,int r){
	if(x==l && y==r) return t[now];
	int mid=(l+r)/2;
	if(y<=mid) return get_tot(ls[now],x,y,l,mid);
	else if(midbound){
				tf[id[x]][y]=true;
				for(int j=0;j=bound) printf("%d\n",get_sum(sum[id[x]],l)-get_sum(sum[id[x]],y-1));
		}
	}
}

 

你可能感兴趣的:(集合求交,51nod1818,根号分治)