GJGHFD的二进制数 题解 [主席树]

GJGHFD的二进制数

Description:

​ 给定一个长度为 $ n $ 的序列 $ a_1 $, \(a_2\), · · · , \(a_n\) ,定义\(F(l, r) =a_l \& a_{l+1} \& · · · \& a_r,S(l, r) = {F(a, b)| min(l, r) \leq a \leq b \leq max(l, r)}\)
​ 其中 ′&′ 表示二进制按位与操作.
​ 现在有 \(q\) 个询问,每个询问给出两个数 \(l, r\) ,请求出集合 \(S(l, r)\) 的大小.

Input:

​ 第一行一个整数 \(n\) ,表示序列长度.
​ 接下来一行 \(n\) 个整数,给出这个序列.
​ 第三行一个整数 \(q\) ,表示询问个数.
​ 接下来 \(q\) 行,每行两个整数 \(l, r\) (\(0 < l, r < 2^{30}\)) ,描述一个询问. 本题强制在线,假设上一次询问的答案为 \(lastans\)(初始时 \(lastans = 0\)),则每次读入的 l, r 需要分别变为 \((l \oplus lastans) \% n + 1\),\((r\oplus lastans) \% n + 1\),其中 ′\(\oplus\)′ 表示二进制按位异或.

Output:

​ 对于每个询问,输出一行一个整数表示答案.

Sample Input:

5
15 14 13 11 7
3
2 5
2 5
2 5

Sample Output:

4
1
3

Hint:

​ 对于\(30\%\)的数据,\(1 \leq n,q \leq 100\)

​ 对于\(60\%\)的数据,\(1 \leq n,q \leq 2000\)

​ 对于\(100\%\)的数据,\(1 \leq n,q \leq 10^5.0 \leq a_i < 2^{30}\)

​ 时间限制: \(2s\)

​ 空间限制: \(512M\)

题目分析:

​ 首先有一个显而易见的性质:我们选定一个\(i\)作为起点,得到的\(F(i,j)\)最多只会有\(log_2{2^{30}}=30\)个不同的数。

​ 所以对于所有区间,得到的\(F(l,r)​\)只会有至多\(30n​\)个不同的数。我们对于每个起点\(i​\),统计出以这个点为起点得到的某个\(F​\)值使得这个值为\(F(i,j)​\)这个最小的\(j​\)为多少。那么这个数会对答案产生贡献当且仅当询问区间为\([L,R]​\)时,\(L \leq i 且j \leq R​\).但是每个相同的数可能会产生重复的贡献,我们对于每个值按照起点\(i​\)从小到大排序,维护单调递增的\(j​\),那么我们就可以用主席树维护并去重了,详情见代码。

​ 代码如下(马蜂很丑,不喜勿喷)——

/*#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define Tp template<typename T>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define maxn 100005
#define N 40000005
#define inf 214748364
using namespace std;
int n,ans,tot,num,a[maxn],q,rt[maxn<<2],rt2[maxn<<2],sum[N],tag[N],trl[N],trr[N],nxt[maxn][35],pos[35],stx[maxn],sty[maxn];
struct node{int v,l,r;}p[maxn*30];
inline bool cmp(const node x,const node y){if(x.v!=y.v) return x.v<y.v;return x.l<y.l;}
inline void modify2(int &now,int l,int r,int ll,int rr,int v){
	if(!now) now=++num;sum[now]+=v;if(l>=ll&&r<=rr){tag[now]+=v;return;}int mid=l+r>>1;
	if(mid>=ll) modify2(trl[now],l,mid,ll,rr,v);if(mid<rr) modify2(trr[now],mid+1,r,ll,rr,v);
}
inline int query2(int now,int l,int r,int ll,int rr){
	if(!now) return 0;if(l>=ll&&r<=rr) return sum[now];int mid=l+r>>1,res=tag[now];
	if(mid>=ll) res+=query2(trl[now],l,mid,ll,rr);if(mid<rr) res+=query2(trr[now],mid+1,r,ll,rr);return res;
}
inline void modify(int now,int l,int r,int ll,int rr,int l2,int r2,int v){
	modify2(rt[now],1,n,l2,r2,v);if(l>=ll&&r<=rr){modify2(rt2[now],1,n,l2,r2,v);return;}int mid=l+r>>1;
	if(mid>=ll) modify(now<<1,l,mid,ll,rr,l2,r2,v);if(mid<rr) modify(now<<1|1,mid+1,r,ll,rr,l2,r2,v);
}
inline int query(int now,int l,int r,int ll,int rr,int l2,int r2){
	if(l>=ll&&r<=rr) return query2(rt[now],1,n,l2,r2);int mid=l+r>>1,res=query2(rt2[now],1,n,l2,r2);
	if(mid>=ll) res+=query(now<<1,l,mid,ll,rr,l2,r2);if(mid<rr) res+=query(now<<1|1,mid+1,r,ll,rr,l2,r2);return res;
}
class FileInputOutput
{
	private:
		static const int S=1<<21;
		#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
		#define pc(ch) (Ftop!=Fend?*Ftop++=ch:(fwrite(Fout,1,S,stdout),*(Ftop=Fout)++=ch))
		char Fin[S],Fout[S],*A,*B,*Ftop,*Fend; int pt[25];
	public:
		FileInputOutput(void) { Ftop=Fout; Fend=Fout+S; }
		Tp inline void read(T& x)
		{
			x=0; char ch; while (!isdigit(ch=tc()));
			while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
		}
		Tp inline void write(T x,const char& ch)
		{
			if (x<0) pc('-'),x=-x; RI ptop=0; while (pt[++ptop]=x%10,x/=10);
			while (ptop) pc(pt[ptop--]+48); pc(ch);
		}
		inline void flush(void)
		{
			fwrite(Fout,1,Ftop-Fout,stdout);
		}
		#undef tc
		#undef pc
}F;
int main(){
	F.read(n);for(register int i=1;i<=n;i++) F.read(a[i]);for(register int i=0;i<30;i++) pos[i]=n+1;
	for(register int i=n;i;i--) for(register int j=0;j<30;j++){nxt[i][j]=pos[j];if(!(a[i]>>j&1)) pos[j]=i;}
	for(register int i=1;i<=n;i++){
		int now=i,sum=a[i];p[++tot]=node{sum,i,i};while(1){
			int tmp=n+1;for(register int j=0;j<30;j++) if(sum>>j&1) tmp=min(tmp,nxt[now][j]);
			if(tmp==n+1) break;sum&=a[tmp];now=tmp;p[++tot]=node{sum,i,now};
		}
	}
	sort(p+1,p+tot+1,cmp);for(register int i=1;i<=tot;i++){ 
		int now=i;while(now<tot&&p[now+1].v==p[now].v) now++;
		int top=0;for(register int j=i;j<=now;j++){while(top&&p[j].r<=sty[top]) top--;stx[++top]=p[j].l,sty[top]=p[j].r;}
		for(register int j=1;j<=top;j++){modify(1,1,n,stx[j],stx[j],sty[j],sty[j],1);if(j>1) modify(1,1,n,stx[j-1],stx[j-1],sty[j],sty[j],-1);}i=now;
	}
	F.read(q);while(q--){
		int x,y;F.read(x),F.read(y);x^=ans,y^=ans;x=x%n+1,y=y%n+1;if(x>y) swap(x,y);
		ans=query(1,1,n,x,y,x,y);F.write(ans,'\n');
	}
	return F.flush(),0;
}
*/
/*
10
7 2 7 6 4 3 6 1 6 7 
5
6 6
8 2
2 2
3 6
7 8

树套树它曾经活过,现在死了。。。 
*/
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define Tp template<typename T>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define maxn 100005
#define N 20000005
#define inf 214748364
using namespace std;
int n,ans,tot,num,a[maxn],q,rt[maxn<<2],sum[N],tag[N],trl[N],trr[N],nxt[maxn][35],pos[35],stx[maxn],sty[maxn];
struct node{int v,l,r;}p[maxn*30];
inline bool cmp(const node x,const node y){if(x.v!=y.v) return x.v<y.v;return x.l<y.l;}
inline void modify(int &now,int l,int r,int x,int v){
	if(!now) now=++num;sum[now]+=v;if(l==r) return;int mid=l+r>>1;
	if(mid>=x) modify(trl[now],l,mid,x,v);else modify(trr[now],mid+1,r,x,v);
}
inline int query(int now,int l,int r,int ll,int rr){
	if(!now) return 0;if(l>=ll&&r<=rr) return sum[now];int mid=l+r>>1,res=0;
	if(mid>=ll) res+=query(trl[now],l,mid,ll,rr);if(mid<rr) res+=query(trr[now],mid+1,r,ll,rr);return res;
}
inline void merge(int &now,int lst,int l,int r){
	if(!now){now=lst;return;}else sum[now]+=sum[lst];if(l==r) return;int mid=l+r>>1;
	if(trl[lst]) merge(trl[now],trl[lst],l,mid);if(trr[lst]) merge(trr[now],trr[lst],mid+1,r);
}
class FileInputOutput
{
	private:
		static const int S=1<<21;
		#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
		#define pc(ch) (Ftop!=Fend?*Ftop++=ch:(fwrite(Fout,1,S,stdout),*(Ftop=Fout)++=ch))
		char Fin[S],Fout[S],*A,*B,*Ftop,*Fend; int pt[25];
	public:
		FileInputOutput(void) { Ftop=Fout; Fend=Fout+S; }
		Tp inline void read(T& x)
		{
			x=0; char ch; while (!isdigit(ch=tc()));
			while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
		}
		Tp inline void write(T x,const char& ch)
		{
			if (x<0) pc('-'),x=-x; RI ptop=0; while (pt[++ptop]=x%10,x/=10);
			while (ptop) pc(pt[ptop--]+48); pc(ch);
		}
		inline void flush(void)
		{
			fwrite(Fout,1,Ftop-Fout,stdout);
		}
		#undef tc
		#undef pc
}F;
int main(){
//	freopen("data.in","r",stdin);
//	freopen("jxc.out","w",stdout);
	F.read(n);for(register int i=1;i<=n;i++) F.read(a[i]);for(register int i=0;i<30;i++) pos[i]=n+1;
	for(register int i=n;i;i--) for(register int j=0;j<30;j++){nxt[i][j]=pos[j];if(!(a[i]>>j&1)) pos[j]=i;}
	for(register int i=1;i<=n;i++){
		int now=i,sum=a[i];p[++tot]=node{sum,i,i};while(1){
			int tmp=n+1;for(register int j=0;j<30;j++) if(sum>>j&1) tmp=min(tmp,nxt[now][j]);
			if(tmp==n+1) break;sum&=a[tmp];now=tmp;p[++tot]=node{sum,i,now};
		}
	}
	sort(p+1,p+tot+1,cmp);for(register int i=1;i<=tot;i++){ 
		int now=i;while(now<tot&&p[now+1].v==p[now].v) now++;
		int top=0;for(register int j=i;j<=now;j++){while(top&&p[j].r<=sty[top]) top--;stx[++top]=p[j].l,sty[top]=p[j].r;}
//		for(register int j=1;j<=top;j++) cout<<stx[j]<<' '<<sty[j]<<'\n';puts("");
		for(register int j=1;j<=top;j++){modify(rt[stx[j]],1,n,sty[j],1);if(j>1) modify(rt[stx[j-1]],1,n,sty[j],-1);}i=now;
	}
	for(register int i=2;i<=n;i++) merge(rt[i],rt[i-1],1,n);F.read(q);while(q--){
		int x,y;F.read(x),F.read(y);x^=ans,y^=ans;x=x%n+1,y=y%n+1;if(x>y) swap(x,y);
		ans=query(rt[y],1,n,x,y)-query(rt[x-1],1,n,x,y);F.write(ans,'\n');
	}
	return F.flush(),0;
}
/*
10
2 8 5 1 10 5 9 9 3 5 
5
6 6
8 2
2 2
3 6
7 8

*/
posted @ 2020-12-28 21:06  OdtreePrince  阅读(96)  评论(0编辑  收藏  举报