luogu P4688 [Ynoi2016]掉進兔子洞
阿新 • • 發佈:2020-07-16
bitset優化莫隊。
由於bitset並不能存可重集,所以我們考慮給每種元素在bitset裡留 \(k\) 個位置(\(k\) 為這種元素的個數)。我們只需要在離散化的時候不去重,然後把 \(p\) 放進bitset中第 \(p-cnt_p\) 個位置就行了(\(cnt_p\) 為bitset當前存的 \(p\) 的個數)。
發現數組開不下,我們把詢問分成三段處理就好。
程式碼:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<bitset> #include<cmath> using namespace std; const int N=100009,M=34000; int n,m,a[N],cnt=1,ans1[M],belong[M*3],block,b[N],sum[N]; bitset <N> now,ans[M]; struct Question { int l,r,id; bool operator < (const Question A)const { if(belong[l]!=belong[A.l]) return l<A.l; return (belong[l]&1)?r<A.r:r>A.r; } }q[M*3]; int read() { int x=0; char c=getchar(); while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); return x; } void init() { n=read(),m=read(); for (int i=1;i<=n;i++) a[i]=b[i]=read(); sort(b+1,b+1+n); for (int i=1;i<=n;i++) a[i]=upper_bound(b+1,b+1+n,a[i])-b-1; block=(int)sqrt(N); for (int i=1;i<=(M-10)*3;i++) belong[i]=(i-1)/block+1; } void add(int x) { now[x-sum[x]]=1; sum[x]++; } void del(int x) { sum[x]--; now[x-sum[x]]=0; } void work() { int tot=0,all=0; memset(ans1,0,sizeof(ans1)); for (int i=1;i<=M-10&&cnt<=m;i++,cnt++,all++) tot++,q[tot].l=read(),q[tot].r=read(),ans1[i]+=q[tot].r-q[tot].l+1,q[tot].id=i, tot++,q[tot].l=read(),q[tot].r=read(),ans1[i]+=q[tot].r-q[tot].l+1,q[tot].id=i, tot++,q[tot].l=read(),q[tot].r=read(),ans1[i]+=q[tot].r-q[tot].l+1,q[tot].id=i; sort(q+1,q+1+tot); memset(sum,0,sizeof(sum)); for (int i=1;i<=all;i++) ans[i].set(); now.reset(); int l=1,r=0; for (int i=1;i<=tot;i++) { while(r<q[i].r) add(a[++r]); while(l>q[i].l) add(a[--l]); while(r>q[i].r) del(a[r--]); while(l<q[i].l) del(a[l++]); ans[q[i].id]&=now; } for (int i=1;i<=all;i++) printf("%d\n",ans1[i]-ans[i].count()*3); if(cnt<=m) work(); } int main() { init(); work(); return 0; }