bzoj4939: [Ynoi2016]掉进兔子洞(莫队 + bitset)
https://www.lydsy.com/JudgeOnline/problem.php?id=4939
ans= r1-l1+1 + r2-l2+1 +r3-l3+1 - ∑ min(cnt1[i],cnt2[i],cnt3[i])*3
计算cnt可以用莫队
关键在与如何对3个区间取小
用bitset
假设5个数为 1 5 5 3 3
他们离散化之后为 1 4 4 2 2
那么1对应着bitset的第0位
区间里出现的第一个2对应着bitset的第1位
区间里出现的第二个2对应着bitset的第2位
区间里出现的第一个3对应着bitset的第3位
区间里出现的第二个3对应着bitset的第4位
区间[2,3]的bitset为 0 0 0 1 1
区间[3,4]的bitset为 0 1 0 1 0
这两个bitset执行 & 操作,得到 0 0 0 1 0
1的个数即为 ∑ min(cnt1[i],cnt2[i],cnt3[i])
#include<cmath> #include<cstdio> #include<bitset> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define N 100000 #define T 25000 int a[N+1],b[N+1]; int S,bl[N+1]; bitset<N>F[T+1],f; int cnt[N+1]; bool mark[T+1]; int ans[T+1]; struct node { int id,l,r; }e[T*3+1]; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } } bool cmp(node p,node q) { if(bl[p.l]!=bl[q.l]) return bl[p.l]<bl[q.l]; return p.r<q.r; } void update(int pos,bool ty) { int x=a[pos]; if(ty) { cnt[x]++; f[x+cnt[x]-2]=1; } else { f[x+cnt[x]-2]=0; cnt[x]--; } } void solve(int t) { int n=0; memset(mark,false,sizeof(mark)); memset(ans,0,sizeof(ans)); for(int i=1;i<=t;++i) { read(e[++n].l); read(e[n].r); e[n].id=i; ans[i]+=e[n].r-e[n].l+1; read(e[++n].l); read(e[n].r); e[n].id=i; ans[i]+=e[n].r-e[n].l+1; read(e[++n].l); read(e[n].r); e[n].id=i; ans[i]+=e[n].r-e[n].l+1; } sort(e+1,e+n+1,cmp); f.reset(); memset(cnt,0,sizeof(cnt)); int L=1,R=0; for(int i=1;i<=n;++i) { while(R<e[i].r) update(++R,true); while(R>e[i].r) update(R--,false); while(L<e[i].l) update(L++,false); while(L>e[i].l) update(--L,true); if(!mark[e[i].id]) F[e[i].id]=f,mark[e[i].id]=true; else F[e[i].id]&=f; } for(int i=1;i<=t;++i) { ans[i]-=F[i].count()*3; printf("%d\n",ans[i]); } } int main() { //freopen("xp1.in","r",stdin); //freopen("xp1.ans","w",stdout); int n,m; read(n); read(m); S=sqrt(n); for(int i=1;i<=n;++i) bl[i]=(i-1)/S+1; for(int i=1;i<=n;++i) read(a[i]),b[i]=a[i]; sort(b+1,b+n+1); for(int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+n+1,a[i])-b; while(m) { if(m<=T) solve(m),m=0; else solve(T),m-=T; } return 0; }