zoukankan      html  css  js  c++  java
  • 题解[P7470 岛屿探险]

    原题链接

    题意
    给出一个序列 (a_{1dots n},b_{1dots n})
    每次查询给出一段区间 (l,r) 以及两个数 (c,d)
    问区间 ([l,r]) 内有多少个数满足 (a_ioperatorname{xor}cleq min(b_i,d))

    太久没写 ( ext{cdq}) 竟还能这么快过掉。

    首先,由于询问可加性,区间的限制可以拆为两个 ([1,t]) 的查询。

    于是这就可以以位置为第一维进行 ( ext{cdq}) 分治了。

    然后为了方便地拆掉 (min(b_i,d)),可以将 (geq d)(b_i)(< d) 的,分开统计。

    先是 (b_igeq d)(i) ,此时有 (a_ioperatorname{xor}cleq d)。这是 ( ext{01trie}) 的经典运用。将所有 (a_i) 插到 ( ext{01trie}) 上。查询时在 ( ext{01trie}) 上按着一条 (coperatorname{xor}s=d) 的链 (s) ,这使得前几位 (operatorname{xor}c) 后与 (d) 相同。如果这一位上 (d)(1),则累加上使这一位 (operatorname{xor}c=0) 的数的个数,跳到叶子节点的数的个数同样要算上,此时 (operatorname{xor}c=d)

    而对于 (b_i<d)(i),有 (a_ioperatorname{xor}cleq b_i)。考虑将能使 (a_ioperatorname{xor}cleq b_i)(c) 处打上 (+1) 的标记。维护一条使 (soperatorname{xor}a_i=b_i) 的链 (s),如果这一位上 (b_i)(1),将 (operatorname{xor}a_i) 后这一位为 (0) 的子树打上 (+1) 的标记,跳到的叶子节点同样要打上 (+1) 的标记。查询时按着 (c) 从根开始一路累加被加上的标记和即可。

    时间复杂度为 (O(nlog nlog V))( ext{cdq})( ext{01trie}) 各带一个 (log)

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=5e5+10,K=24;
    int n,m,x,y,l,r,a,b,tot,t_tot,rt,tmp;
    int res[N];bool bx,bw;char ch;
    inline void read(int &x){
    	x=0;ch=getchar();while(ch<48)ch=getchar();
    	while(ch>47)x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    }
    void write(int x){if(x>9)write(x/10);putchar(48+x%10);}
    struct cdq{
    	int i,a,b,id;char opt;cdq()=default;//opt=0:mdf otherwise:inq
    	cdq(int _i,int _a,int _b,char _opt=0,int _id=0)
    		:i(_i),a(_a),b(_b),opt(_opt),id(_id){}
    }q[N],q0[N],qq[N],qq0[N];//min=d for q ; min=b for qq
    bool cmpi(cdq x,cdq y){return x.i^y.i?x.i<y.i:!x.opt;}
    bool cmpq(cdq x,cdq y){return x.b^y.b?x.b>y.b:!x.opt;}
    bool cmpqq(cdq x,cdq y){return x.b^y.b?x.b<y.b:x.opt;}
    struct trie01{int son[2],tag[2],sz;}t[N*(K+1)];
    void update(int &k,int x,int i,int v){
    	if(!k)k=++t_tot;t[k].sz+=v;
    	if(~i)update(t[k].son[(x>>i)&1],x,i-1,v);
    }
    void update(int &k,int x,int w,int i,int v){
    	if(!k)k=++t_tot;
    	bw=(w>>i)&1;bx=bw^((x>>i)&1);
    	if(~i){
    		if(bw)t[k].tag[!bx]+=v;
    		update(t[k].son[bx],x,w,i-1,v);
    	}
    	else t[k].tag[0]+=v;
    }
    void inquiry(int k,int x,int w,int i){
    	if(~i){
    		bw=(w>>i)&1;bx=bw^((x>>i)&1);
    		if(bw)tmp+=t[t[k].son[!bx]].sz;
    		inquiry(t[k].son[bx],x,w,i-1);
    	}
    	else tmp+=t[k].sz;
    }
    void inquiry(int k,int x,int i){
    	if(~i){
    		bx=(x>>i)&1;tmp+=t[k].tag[bx];
    		inquiry(t[k].son[bx],x,i-1);
    	}
    	else tmp+=t[k].tag[0];	
    }
    void solve(int l,int r){
    	if(l^r){
    		int mid=(l+r)>>1,i;
    		solve(l,mid);solve(mid+1,r);
    		merge(q+l,q+mid+1,q+mid+1,q+r+1,q0+l,cmpq);
    		merge(qq+l,qq+mid+1,qq+mid+1,qq+r+1,qq0+l,cmpqq);
    		for(i=l;i<=r;++i)q[i]=q0[i],qq[i]=qq0[i];
    		for(i=l;i<=r;++i){
    			if(q[i].i<=mid&&!q[i].opt)update(rt,q[i].a,K,1);
    			else if(q[i].i>mid&&q[i].opt){
    				tmp=0;inquiry(rt,q[i].a,q[i].b,K);
    				res[q[i].id]+=tmp*q[i].opt;
    			}
    		}
    		for(i=l;i<=r;++i)if(q[i].i<=mid&&!q[i].opt)update(rt,q[i].a,K,-1);
    		for(i=l;i<=r;++i){
    			if(qq[i].i<=mid&&!qq[i].opt)update(rt,qq[i].a,qq[i].b,K,1);
    			else if(qq[i].i>mid&&qq[i].opt){
    				tmp=0;inquiry(rt,qq[i].a,K);
    				res[qq[i].id]+=tmp*qq[i].opt;
    			}
    		}
    		for(i=l;i<=r;++i)if(qq[i].i<=mid&&!qq[i].opt)update(rt,qq[i].a,qq[i].b,K,-1);
    	}
    }
    main(){
    	read(n);read(m);register int i;
    	for(i=1;i<=n;++i)read(a),read(b),q[++tot]=cdq(i,a,b);
    	for(i=1;i<=m;++i){
    		read(l),read(r),read(a),read(b);
    		q[++tot]=cdq(r,a,b,1,i);
    		if(l>1)q[++tot]=cdq(l-1,a,b,-1,i);
    	}
    	sort(q+1,q+tot+1,cmpi);
    	for(i=1;i<=tot;++i)q[i].i=i;
    	for(i=1;i<=tot;++i)qq[i]=q[i];
    	solve(1,tot);
    	for(i=1;i<=m;++i)write(res[i]),putchar('
    ');
    }
    
  • 相关阅读:
    【转】extern "C"的含义和用法
    python的shelve库
    【转】TCP是流传输协议,UDP是包传输协议
    【转】TCP慢启动、拥塞避免、快速重传、快速恢复
    【转】C/C++多线程编程中什么情况下需要加volatile?
    【转】C++对象是创建在堆上,还是在栈上?
    【转】腾讯高级工程师:一道面试题引发的高并发性能调试思考
    【转】C++类的sizeof大小
    【转】C编译器内存对齐
    【转】c++中使用memset初始化类对象
  • 原文地址:https://www.cnblogs.com/Y-B-X/p/15489257.html
Copyright © 2011-2022 走看看