1. 程式人生 > 實用技巧 >GJGHFD的二進位制數 題解 [主席樹]

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

*/