牛客多校 Interval 主席树套路

题意就不说了  

这样的题乍一看感觉区间& 会有n^2级别个不同的数   其实仔细分析是没有那么多的  

我们考虑维护一个map   这个map记录了当前位置以前的数&起来后可以得到的值以及他们的位置 (是连续的 可以理解为后缀&) 那么我们加入当前位置的数  并且与map中的值进行&操作(这一步我们最多得到logn个值) 

然后就是一个主席树的套路了  对于在前面出现过的值 我们把它的位置-1  并且在当前位置+1 然后更新这个值的位置为当前位置  这个题可以算是区间不同数个数的一个升级版把  

复杂度上限是 nlogn^2 

 

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+100;
int sum[N*400],ls[N*400],rs[N*400],tot,rt[N];
map<int,int>las,mp,temp;
void update(int &o,int l,int r,int pos,int val){
	++tot;sum[tot]=sum[o]+val;
	ls[tot]=ls[o];rs[tot]=rs[o];
	o=tot;
	if(l==r) return;
	int mid = l+r>>1;
	if(pos<=mid) update(ls[o],l,mid,pos,val);
	else update(rs[o],mid+1,r,pos,val);
}
int query(int o,int l,int r,int L,int R){
	if(L<=l&&R>=r) return sum[o];
	int mid = l+r>>1,ans = 0;
	if(L<=mid) ans+=query(ls[o],l,mid,L,R);
	if(R>mid) ans+=query(rs[o],mid+1,r,L,R);
	return ans;
}
int main(){
	int n;
	scanf("%d",&n);
	for(int i = 1; i <= n; i++){
		int x;
		rt[i]=rt[i-1];
		scanf("%d",&x);
		mp[x]=i;
		temp.clear();
		for(auto it = mp.begin(); it!=mp.end(); ++it){
			int fir = it->first;
			int sec = it->second;
			temp[x&fir]=max(temp[x&fir],sec);
		}
		for(auto it = temp.begin(); it!=temp.end(); ++it){
			int fir = it->first;
			int sec = it->second;
			if(las[fir]!=sec){
				if(las[fir]) update(rt[i],1,n,las[fir],-1);
				las[fir]=sec;
				update(rt[i],1,n,las[fir],1);
			}
		}
		mp=temp;
	}
	int q;
	scanf("%d",&q);
	int lasans=0;
	while(q--){
		int l,r;
		scanf("%d%d",&l,&r);
		l=(l^lasans)%n+1;
		r=(r^lasans)%n+1;
		if(l>r) swap(l,r);
		printf("%d\n",lasans=query(rt[r],1,n,l,r)); 
	}
	return 0;
} 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值