zoukankan      html  css  js  c++  java
  • 【洛谷4688】[Ynoi2016] 掉进兔子洞(莫队+bitset)

    点此看题面

    • 给定一个长度为(n)的序列。
    • (q)次询问,每次给定三个区间,把三个区间中同时出现的数一个一个删掉,求最后剩下的数的总个数。
    • (n,mle10^5)

    经典(Ynoi)套餐:莫队+(bitset)

    作为一道(Ynoi)来说应该算是比较水的了吧。

    显然,答案应该是三个区间中数的总个数减去(3 imes)在三个区间中同时出现的数的个数

    假设一个区间中没有重复的数,我们只要用(bitset)就能维护出这个区间中出现了哪些数,把三个区间的(bitset)按位与在一起,剩余的(1)的个数就是在三个区间中同时出现的数的个数。

    但问题在于有重复的数,不过其实没什么大关系。只要我们在离散化的时候不对排序后的数组使用(unique),然后假设一个数离散化后对应的数为(x),那么第二次出现就令它等于(x+1),第三次出现等于(x+2),那么就可以让重复的数变得不再重复了。

    而要求出这样子的一个(bitset),显然只能考虑莫队了。

    注意(n imes m)(bitset)开不下,一个经典处理方式把询问分成若干组分别搞(例如(4)组),然后就能卡过内存了。

    代码:(O(nsqrt n+frac{nm}{32}))

    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #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 N 100000
    using namespace std;
    int n,m,a[N+5],p[N+5],dv[N+5],sz,bl[N+5],ans[N/4+5];bitset<N+5> s,S[N/4+5];
    struct Q
    {
    	int p,l,r;I Q(CI i=0,CI a=0,CI b=0):p(i),l(a),r(b){}
    	I bool operator < (Con Q& o) Con {return bl[l]^bl[o.l]?l<o.l:(bl[l]&1?r<o.r:r>o.r);}
    }q[3*N+5];
    namespace FastIO
    {
    	#define FS 100000
    	#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
    	#define pc(c) (FC==FE&&(clear(),0),*FC++=c)
    	int OT;char oc,FI[FS],FO[FS],OS[FS],*FA=FI,*FB=FI,*FC=FO,*FE=FO+FS;
    	I void clear() {fwrite(FO,1,FC-FO,stdout),FC=FO;}
    	Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
    	Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    	Tp I void writeln(Ty x) {W(OS[++OT]=x%10+48,x/=10);W(OT) pc(OS[OT--]);pc('
    ');}
    }using namespace FastIO;
    I void Mo(Q* q,CI m)//莫队
    {
    	#define A(x) (s.set(p[x]++))//插入一个元素
    	#define D(x) (s.reset(--p[x]))//删除一个元素
    	RI i,L=1,R=0;for(sort(q+1,q+m+1),i=1;i<=m;ans[q[i].p]+=q[i].r-q[i].l+1,S[q[i].p]&=s,++i)//统计每个询问的结果
    		{W(R<q[i].r) A(a[++R]);W(L>q[i].l) A(a[--L]);W(R>q[i].r) D(a[R--]);W(L<q[i].l) D(a[L++]);}//移动区间
    	W(L<=R) D(a[L++]);//清空
    }
    I void Solve(CI l,CI r)//处理[l,r]中的询问
    {
    	RI i;for(i=l;i<=r;++i) ans[q[3*i-2].p=q[3*i-1].p=q[3*i].p=i-l+1]=0,S[i-l+1].set();
    	for(Mo(q+3*(l-1),3*(r-l+1)),i=1;i<=r-l+1;++i) writeln(ans[i]-3*S[i].count());//总个数-3*共同个数
    }
    int main()
    {
    	RI i;for(read(n,m),sz=sqrt(n),i=1;i<=n;++i) read(a[i]),dv[i]=a[i],bl[i]=(i-1)/sz+1;//对序列分块
    	for(i=1;i<=m;++i) read(q[3*i-2].l,q[3*i-2].r,q[3*i-1].l,q[3*i-1].r,q[3*i].l,q[3*i].r);
    	for(sort(dv+1,dv+n+1),i=1;i<=n;++i) p[a[i]=lower_bound(dv+1,dv+n+1,a[i])-dv]=a[i];//离散化,不unique
    	m<=N/4?Solve(1,m):(Solve(1,m/4),Solve(m/4+1,m/4*2),Solve(m/4*2+1,m/4*3),Solve(m/4*3+1,m));//分4组求解卡内存
    	return clear(),0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    【回溯】数字排列问题
    Price List
    NanoApe Loves Sequence-待解决
    【回溯】n皇后问题
    安卓 学习之旅 入门
    mysql链接 显示 error: 'Access denied for user 'root'@'localhost' (using password: NO)'
    javaweb 实战_1
    java 插件安装
    leetcode 最长有效括号
    hdu 1074 Doing Homework
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu4688.html
Copyright © 2011-2022 走看看