【LOJ #6100】「2017 山东二轮集训 Day1」第一题(主席树)

传送门

考虑求出每个位置能向右延伸的最远距离后即可用主席树维护区间加区间求和做

考虑求出 f [ 0 / 1 ] [ i ] [ j ] f[0/1][i][j] 表示前 i i 个位置,第 j j 位作为最高位时从 0 ( 1 ) 0(1) 变成 1 ( 0 ) 1(0) 的次数

然后对于每个数 l l 二分右端点
如果 l 1 l-1 时前缀 j j 位异或和为 1 1 ,那么由于实际从 i i 开始为 0 0 ,就看 l r l-r 中间是否有从 0 0 变成 1 1 的次数,如果有,那么也就是这一位存在 0 > 1 > 0 0->1->0 的情况,也就是不合法
对于异或和为 0 0 类似

然后主席树维护,每次差分询问即可

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define re register
#define pb push_back
#define pii pair<int,int>
#define ll long long
#define fi first
#define se second
#define bg begin
cs int RLEN=1<<20|1;
inline char gc(){
    static char ibuf[RLEN],*ib,*ob;
    (ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    return (ib==ob)?EOF:*ib++;
}
inline ll readll(){
    char ch=gc();
    ll res=0;bool f=1;
    while(!isdigit(ch))f^=ch=='-',ch=gc();
    while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    return f?res:-res;
}
inline int read(){
    char ch=gc();
    int res=0;bool f=1;
    while(!isdigit(ch))f^=ch=='-',ch=gc();
    while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    return f?res:-res;
}
template<class tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<class tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int N=100005,M=30;
namespace Seg{
	cs int N=::N*60;
	int lc[N],rc[N],tag[N],tot;
	ll s[N];
	#define mid ((l+r)>>1)
	inline int copy(int r1){
		int u=++tot;lc[u]=lc[r1],rc[u]=rc[r1],tag[u]=tag[r1],s[u]=s[r1];
		return u;
	}
	void update(int &u,int l,int r,int st,int des,int k){
		u=copy(u);
		if(st<=l&&r<=des){tag[u]+=k,s[u]+=(r-l+1)*k;return;}
		if(st<=mid)update(lc[u],l,mid,st,des,k);
		if(mid<des)update(rc[u],mid+1,r,st,des,k);
		s[u]=s[lc[u]]+s[rc[u]]+1ll*(r-l+1)*tag[u];
	}
	ll query(int r1,int r2,int l,int r,int st,int des){
		if(!r1&&!r2)return 0;
		if(st<=l&&r<=des)return s[r2]-s[r1];
		ll res=1ll*(min(des,r)-max(l,st)+1)*(tag[r2]-tag[r1]);
		if(st<=mid)res+=query(lc[r1],lc[r2],l,mid,st,des);
		if(mid<des)res+=query(rc[r1],rc[r2],mid+1,r,st,des);
		return res;
	}
	#undef mid
}
int n,m;
int f[2][N][M],s[N],a[N],rt[N];
inline bool check(int l,int r){
	for(int j=29;~j;j--){
		if((s[l-1]&(1<<j))&&(f[0][r][j]-f[0][l-1][j]))return 0;
		if(!(s[l-1]&(1<<j))&&(f[1][r][j]-f[1][l-1][j]))return 0;
	}
	return 1;
}
inline int getnxt(int pos){
	int l=pos,r=n,res=pos;
	while(l<=r){
		int mid=(l+r)>>1;
		if(check(pos,mid))l=mid+1,res=mid;
		else r=mid-1;
	}//cout<<res<<'\n';
	return res;
}
ll last;
int main(){
	#ifdef Stargazer
	freopen("lx.in","r",stdin);
//	freopen("my.out","w",stdout);
	#endif
	n=read();
	for(int i=1;i<=n;i++)a[i]=read(),s[i]=s[i-1]^a[i];
	for(int i=1;i<=n;i++){
		for(int t=0;t<2;t++)
		for(int j=0;j<30;j++)f[t][i][j]=f[t][i-1][j];
		int ps=-1;
		for(int j=29;~j;j--)if(a[i]&(1<<j)){ps=j;break;}
		if(~ps){
			if(s[i-1]&(1<<ps))f[1][i][ps]++;
			else f[0][i][ps]++;
		}
	}
	for(int i=1;i<=n;i++)rt[i]=rt[i-1],Seg::update(rt[i],1,n,i,getnxt(i),1);
	int q=read();
	while(q--){
		int l=(readll()+last)%n+1,r=(readll()+last)%n+1;
		if(l>r)swap(l,r);
		cout<<(last=Seg::query(rt[l-1],rt[r],1,n,l,r))<<'\n';
	}
	return 0;
}
发布了589 篇原创文章 · 获赞 194 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/qq_42555009/article/details/104399143