zoukankan      html  css  js  c++  java
  • 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),((roplus 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,'
    ');
    	}
    	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]<<'
    ';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,'
    ');
    	}
    	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
    
    */
    
  • 相关阅读:
    SANBA服务和FTP服务
    rpm和yum软件管理
    Linux进程管理
    Linux网络技术管理
    RAID磁盘阵列及CentOS7启动流程
    Linux磁盘管理及Lvm
    Linux计划任务及压缩归档
    Linux权限管理
    Linux用户及用户组管理
    vim 编辑器
  • 原文地址:https://www.cnblogs.com/jiangxuancheng/p/14203629.html
Copyright © 2011-2022 走看看